diff --git a/libpurple/purpleprotocolfiletransfer.h b/libpurple/purpleprotocolfiletransfer.h
--- a/libpurple/purpleprotocolfiletransfer.h
+++ b/libpurple/purpleprotocolfiletransfer.h
@@ -36,6 +36,17 @@
 
 #define PURPLE_TYPE_PROTOCOL_FILE_TRANSFER (purple_protocol_file_transfer_get_type())
 
+/**
+ * PURPLE_PROTOCOL_FILE_TRANSFER_ERROR:
+ *
+ * A constant for protocol file transfer errors.
+ *
+ * Since: 3.0
+ */
+#define PURPLE_PROTOCOL_FILE_TRANSFER_ERROR \
+	(g_quark_from_static_string("purple-protocol-file-transfer")) \
+	PURPLE_AVAILABLE_MACRO_IN_3_0
+
 PURPLE_AVAILABLE_IN_3_0
 G_DECLARE_INTERFACE(PurpleProtocolFileTransfer,
                     purple_protocol_file_transfer, PURPLE,
# HG changeset patch
# Node ID c0e339966c63a498c695e949493efee771bce8d3
# Parent  2973a9b3d225b1fd089eb221d8e105aeed386d24
diff --git a/libpurple/purpleprotocolfiletransfer.c b/libpurple/purpleprotocolfiletransfer.c
--- a/libpurple/purpleprotocolfiletransfer.c
+++ b/libpurple/purpleprotocolfiletransfer.c
@@ -50,8 +50,11 @@
 	if(iface != NULL && iface->send_async != NULL) {
 		iface->send_async(protocol, transfer, callback, data);
 	} else {
-		g_warning("%s does not implement send_async",
-		          G_OBJECT_TYPE_NAME(protocol));
+		g_task_report_new_error(G_OBJECT(protocol), callback, data,
+		                        purple_protocol_file_transfer_send_async,
+		                        PURPLE_PROTOCOL_FILE_TRANSFER_ERROR, 0,
+		                        "%s does not implement send_async",
+		                        G_OBJECT_TYPE_NAME(protocol));
 	}
 }
 
@@ -63,15 +66,22 @@
 	PurpleProtocolFileTransferInterface *iface = NULL;
 
 	g_return_val_if_fail(PURPLE_IS_PROTOCOL_FILE_TRANSFER(protocol), FALSE);
+	g_return_val_if_fail(G_IS_ASYNC_RESULT(result), FALSE);
+
+	if(g_async_result_is_tagged(result,
+	                            purple_protocol_file_transfer_send_async))
+	{
+		return g_task_propagate_boolean(G_TASK(result), error);
+	}
 
 	iface = PURPLE_PROTOCOL_FILE_TRANSFER_GET_IFACE(protocol);
 	if(iface != NULL && iface->send_finish != NULL) {
 		return iface->send_finish(protocol, result, error);
-	} else {
-		g_warning("%s does not implement send_finish",
-		          G_OBJECT_TYPE_NAME(protocol));
 	}
 
+	g_warning("purple_protocol_file_transfer_send_finish called without "
+	          "calling purple_protocol_file_transfer_send_async");
+
 	return FALSE;
 }
 
@@ -89,8 +99,11 @@
 	if(iface != NULL && iface->receive_async != NULL) {
 		iface->receive_async(protocol, transfer, callback, data);
 	} else {
-		g_warning("%s does not implement receive_async",
-		          G_OBJECT_TYPE_NAME(protocol));
+		g_task_report_new_error(G_OBJECT(protocol), callback, data,
+		                        purple_protocol_file_transfer_receive_async,
+		                        PURPLE_PROTOCOL_FILE_TRANSFER_ERROR, 0,
+		                        "%s does not implement receive_async",
+		                        G_OBJECT_TYPE_NAME(protocol));
 	}
 }
 
@@ -102,14 +115,21 @@
 	PurpleProtocolFileTransferInterface *iface = NULL;
 
 	g_return_val_if_fail(PURPLE_IS_PROTOCOL_FILE_TRANSFER(protocol), FALSE);
+	g_return_val_if_fail(G_IS_ASYNC_RESULT(result), FALSE);
+
+	if(g_async_result_is_tagged(result,
+	                            purple_protocol_file_transfer_receive_async))
+	{
+		return g_task_propagate_boolean(G_TASK(result), error);
+	}
 
 	iface = PURPLE_PROTOCOL_FILE_TRANSFER_GET_IFACE(protocol);
 	if(iface != NULL && iface->receive_finish != NULL) {
 		return iface->receive_finish(protocol, result, error);
-	} else {
-		g_warning("%s does not implement receive_finish",
-		          G_OBJECT_TYPE_NAME(protocol));
 	}
 
+	g_warning("purple_protocol_file_transfer_receive_finish called without "
+	          "calling purple_protocol_file_transfer_receive_async");
+
 	return FALSE;
 }
diff --git a/libpurple/tests/test_protocol_file_transfer.c b/libpurple/tests/test_protocol_file_transfer.c
--- a/libpurple/tests/test_protocol_file_transfer.c
+++ b/libpurple/tests/test_protocol_file_transfer.c
@@ -85,119 +85,101 @@
  * TestProtocolFileTransferEmpty Tests
  *****************************************************************************/
 static void
-test_purple_protocol_file_transfer_empty_send_async(gconstpointer data) {
-	if(g_test_subprocess()) {
-		PurpleAccount *account = NULL;
-		PurpleContactInfo *remote = NULL;
-		PurpleFileTransfer *transfer = NULL;
-		PurpleProtocolFileTransfer *protocol_file_transfer = NULL;
-		GFile *local_file = NULL;
-
-		account = purple_account_new("test", "test");
-		remote = purple_contact_info_new(NULL);
-		local_file = g_file_new_for_path(data);
+test_purple_protocol_file_transfer_empty_send_cb(GObject *source,
+                                                 GAsyncResult *result,
+                                                 G_GNUC_UNUSED gpointer data)
+{
+	PurpleProtocolFileTransfer *protocol = NULL;
+	GError *error = NULL;
+	gboolean success = FALSE;
 
-		transfer = purple_file_transfer_new_send(account, remote, local_file);
-		g_clear_object(&account);
-		g_clear_object(&remote);
-		g_clear_object(&local_file);
-
-		protocol_file_transfer = g_object_new(test_purple_protocol_file_transfer_empty_get_type(),
-		                                      NULL);
+	g_assert_true(PURPLE_IS_PROTOCOL_FILE_TRANSFER(source));
+	protocol = PURPLE_PROTOCOL_FILE_TRANSFER(source);
 
-		purple_protocol_file_transfer_send_async(protocol_file_transfer,
-		                                         transfer, NULL, NULL);
-
-		g_clear_object(&transfer);
-		g_clear_object(&protocol_file_transfer);
-	}
-
-	g_test_trap_subprocess(NULL, 0, 0);
-	g_test_trap_assert_stderr("*Purple-WARNING*TestPurpleProtocolFileTransferEmpty*send_async*");
+	success = purple_protocol_file_transfer_send_finish(protocol, result,
+	                                                    &error);
+	g_assert_error(error, PURPLE_PROTOCOL_FILE_TRANSFER_ERROR, 0);
+	g_clear_error(&error);
+	g_assert_false(success);
 }
 
 static void
-test_purple_protocol_file_transfer_empty_send_finish(void) {
-	if(g_test_subprocess()) {
-		PurpleProtocolFileTransfer *protocol_file_transfer = NULL;
-		GError *error = NULL;
-		GTask *task = NULL;
-		gboolean result = FALSE;
+test_purple_protocol_file_transfer_empty_send(gconstpointer data) {
+	PurpleAccount *account = NULL;
+	PurpleContactInfo *remote = NULL;
+	PurpleFileTransfer *transfer = NULL;
+	PurpleProtocolFileTransfer *protocol_file_transfer = NULL;
+	GFile *local_file = NULL;
 
-		protocol_file_transfer = g_object_new(test_purple_protocol_file_transfer_empty_get_type(),
-		                                      NULL);
-
-		task = g_task_new(protocol_file_transfer, NULL, NULL, NULL);
+	account = purple_account_new("test", "test");
+	remote = purple_contact_info_new(NULL);
+	local_file = g_file_new_for_path(data);
 
-		result = purple_protocol_file_transfer_send_finish(protocol_file_transfer,
-		                                                   G_ASYNC_RESULT(task),
-		                                                   &error);
-		g_assert_no_error(error);
-		g_assert_false(result);
+	transfer = purple_file_transfer_new_send(account, remote, local_file);
+	g_clear_object(&account);
+	g_clear_object(&remote);
+	g_clear_object(&local_file);
+
+	protocol_file_transfer = g_object_new(test_purple_protocol_file_transfer_empty_get_type(),
+	                                      NULL);
 
-		g_clear_object(&task);
-		g_clear_object(&protocol_file_transfer);
-	}
+	purple_protocol_file_transfer_send_async(protocol_file_transfer,
+	                                         transfer,
+	                                         test_purple_protocol_file_transfer_empty_send_cb,
+	                                         NULL);
 
-	g_test_trap_subprocess(NULL, 0, 0);
-	g_test_trap_assert_stderr("*Purple-WARNING*TestPurpleProtocolFileTransferEmpty*send_finish*");
+	g_main_context_iteration(NULL, FALSE);
+
+	g_assert_finalize_object(transfer);
+	g_assert_finalize_object(protocol_file_transfer);
 }
 
 static void
-test_purple_protocol_file_transfer_empty_receive_async(void) {
-	if(g_test_subprocess()) {
-		PurpleAccount *account = NULL;
-		PurpleContactInfo *remote = NULL;
-		PurpleFileTransfer *transfer = NULL;
-		PurpleProtocolFileTransfer *protocol_file_transfer = NULL;
-
-		account = purple_account_new("test", "test");
-		remote = purple_contact_info_new(NULL);
+test_purple_protocol_file_transfer_empty_receive_cb(GObject *source,
+                                                    GAsyncResult *result,
+                                                    G_GNUC_UNUSED gpointer data)
+{
+	PurpleProtocolFileTransfer *protocol = NULL;
+	GError *error = NULL;
+	gboolean success = FALSE;
 
-		transfer = purple_file_transfer_new_receive(account, remote,
-		                                            "file.png", 0);
-		g_clear_object(&account);
-		g_clear_object(&remote);
-
-		protocol_file_transfer = g_object_new(test_purple_protocol_file_transfer_empty_get_type(),
-		                                      NULL);
+	g_assert_true(PURPLE_IS_PROTOCOL_FILE_TRANSFER(source));
+	protocol = PURPLE_PROTOCOL_FILE_TRANSFER(source);
 
-		purple_protocol_file_transfer_receive_async(protocol_file_transfer,
-		                                            transfer, NULL, NULL);
-
-		g_clear_object(&transfer);
-		g_clear_object(&protocol_file_transfer);
-	}
-
-	g_test_trap_subprocess(NULL, 0, 0);
-	g_test_trap_assert_stderr("*Purple-WARNING*TestPurpleProtocolFileTransferEmpty*receive_async*");
+	success = purple_protocol_file_transfer_receive_finish(protocol, result,
+	                                                       &error);
+	g_assert_error(error, PURPLE_PROTOCOL_FILE_TRANSFER_ERROR, 0);
+	g_clear_error(&error);
+	g_assert_false(success);
 }
 
 static void
-test_purple_protocol_file_transfer_empty_receive_finish(void) {
-	if(g_test_subprocess()) {
-		PurpleProtocolFileTransfer *protocol_file_transfer = NULL;
-		GError *error = NULL;
-		GTask *task = NULL;
-		gboolean result = FALSE;
+test_purple_protocol_file_transfer_empty_receive(void) {
+	PurpleAccount *account = NULL;
+	PurpleContactInfo *remote = NULL;
+	PurpleFileTransfer *transfer = NULL;
+	PurpleProtocolFileTransfer *protocol_file_transfer = NULL;
 
-		protocol_file_transfer = g_object_new(test_purple_protocol_file_transfer_empty_get_type(),
-		                                      NULL);
-
-		task = g_task_new(protocol_file_transfer, NULL, NULL, NULL);
+	account = purple_account_new("test", "test");
+	remote = purple_contact_info_new(NULL);
 
-		result = purple_protocol_file_transfer_receive_finish(protocol_file_transfer,
-		                                                      G_ASYNC_RESULT(task),
-		                                                      &error);
-		g_assert_no_error(error);
-		g_assert_false(result);
+	transfer = purple_file_transfer_new_receive(account, remote,
+	                                            "file.png", 0);
+	g_clear_object(&account);
+	g_clear_object(&remote);
+
+	protocol_file_transfer = g_object_new(test_purple_protocol_file_transfer_empty_get_type(),
+	                                      NULL);
 
-		g_clear_object(&task);
-		g_clear_object(&protocol_file_transfer);
-	}
+	purple_protocol_file_transfer_receive_async(protocol_file_transfer,
+	                                            transfer,
+	                                            test_purple_protocol_file_transfer_empty_receive_cb,
+	                                            NULL);
 
-	g_test_trap_subprocess(NULL, 0, 0);
-	g_test_trap_assert_stderr("*Purple-WARNING*TestPurpleProtocolFileTransferEmpty*receive_finish*");
+	g_main_context_iteration(NULL, FALSE);
+
+	g_assert_finalize_object(transfer);
+	g_assert_finalize_object(protocol_file_transfer);
 }
 
 /******************************************************************************
@@ -536,18 +518,16 @@
 
 	g_test_init(&argc, &argv, NULL);
 
+	g_test_set_nonfatal_assertions();
+
 	test_ui_purple_init();
 
 	loop = g_main_loop_new(NULL, FALSE);
 
-	g_test_add_data_func("/protocol-contacts/empty/send-async", argv[0],
-	                     test_purple_protocol_file_transfer_empty_send_async);
-	g_test_add_func("/protocol-contacts/empty/send-finish",
-	                test_purple_protocol_file_transfer_empty_send_finish);
-	g_test_add_func("/protocol-contacts/empty/receive-async",
-	                test_purple_protocol_file_transfer_empty_receive_async);
-	g_test_add_func("/protocol-contacts/empty/receive-finish",
-	                test_purple_protocol_file_transfer_empty_receive_finish);
+	g_test_add_data_func("/protocol-contacts/empty/send", argv[0],
+	                     test_purple_protocol_file_transfer_empty_send);
+	g_test_add_func("/protocol-contacts/empty/receive",
+	                test_purple_protocol_file_transfer_empty_receive);
 
 	g_test_add_data_func("/protocol-contacts/normal/send-normal", argv[0],
 	                     test_purple_protocol_file_transfer_send_normal);
