diff --git a/src/libostree/ostree-fetcher.c b/src/libostree/ostree-fetcher.c
index ee74982..dbf225b 100644
--- a/src/libostree/ostree-fetcher.c
+++ b/src/libostree/ostree-fetcher.c
@@ -113,6 +113,9 @@ struct OstreeFetcher
   gint outstanding;
   GQueue pending_queue;
   gint max_outstanding;
+
+  /* Used to cancel a batch of pending requests. */
+  GCancellable *cancellable;
 };
 
 G_DEFINE_TYPE (OstreeFetcher, _ostree_fetcher, G_TYPE_OBJECT)
@@ -126,6 +129,7 @@ _ostree_fetcher_finalize (GObject *object)
 
   g_clear_object (&self->session);
   g_clear_object (&self->client_cert);
+  g_clear_object (&self->cancellable);
 
   g_hash_table_destroy (self->sending_messages);
   g_hash_table_destroy (self->message_to_request);
@@ -211,6 +215,8 @@ _ostree_fetcher_init (OstreeFetcher *self)
   self->message_to_request = g_hash_table_new_full (NULL, NULL, (GDestroyNotify)g_object_unref,
                                                     (GDestroyNotify)pending_uri_free);
   self->output_stream_set = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
+
+  self->cancellable = g_cancellable_new ();
 }
 
 OstreeFetcher *
@@ -528,6 +534,12 @@ on_request_sent (GObject        *object,
       g_simple_async_result_take_error (pending->result, local_error);
       g_simple_async_result_complete (pending->result);
       g_object_unref (pending->result);
+
+      /* Cancel any other pending operations in which a GCancellable
+       * was not explicitly provided.  Do this after completing this
+       * operation or the cancellation will override the real error. */
+      if (pending->cancellable == pending->self->cancellable)
+        g_cancellable_cancel (pending->self->cancellable);
     }
 }
 
@@ -553,7 +565,10 @@ ostree_fetcher_request_uri_internal (OstreeFetcher         *self,
   pending->priority = priority;
   pending->max_size = max_size;
   pending->is_stream = is_stream;
-  pending->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+  if (cancellable != NULL)
+    pending->cancellable = g_object_ref (cancellable);
+  else
+    pending->cancellable = g_object_ref (self->cancellable);
   pending->result = g_simple_async_result_new ((GObject*) self,
                                                callback,
                                                user_data,
@@ -800,3 +815,11 @@ _ostree_fetcher_request_uri_to_membuf (OstreeFetcher  *fetcher,
   g_clear_object (&(data.result_stream));
   return ret;
 }
+
+GCancellable *
+_ostree_fetcher_get_cancellable (OstreeFetcher *fetcher)
+{
+  g_return_val_if_fail (OSTREE_IS_FETCHER (fetcher), NULL);
+
+  return fetcher->cancellable;
+}
diff --git a/src/libostree/ostree-fetcher.h b/src/libostree/ostree-fetcher.h
index 0411277..35f3d22 100644
--- a/src/libostree/ostree-fetcher.h
+++ b/src/libostree/ostree-fetcher.h
@@ -91,6 +91,9 @@ gboolean _ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher,
                                                 guint64        max_size,
                                                 GCancellable   *cancellable,
                                                 GError         **error);
+
+GCancellable * _ostree_fetcher_get_cancellable (OstreeFetcher *fetcher);
+
 G_END_DECLS
 
 #endif
diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c
index cf576b5..35c100e 100644
--- a/src/libostree/ostree-repo-pull.c
+++ b/src/libostree/ostree-repo-pull.c
@@ -1236,11 +1236,13 @@ enqueue_one_object_request (OtPullData        *pull_data,
   else
     expected_max_size = 0;
 
+  /* Don't pass our GCancellable.  OstreeFetcher will use its own internal
+   * GCancellable so pending requests will be cancelled on the first error. */
   _ostree_fetcher_request_uri_with_partial_async (pull_data->fetcher, obj_uri,
                                                   expected_max_size,
                                                   is_meta ? OSTREE_REPO_PULL_METADATA_PRIORITY
                                                           : OSTREE_REPO_PULL_CONTENT_PRIORITY,
-                                                  pull_data->cancellable,
+                                                  NULL,
                                                   is_meta ? meta_fetch_on_complete : content_fetch_on_complete, fetch_data);
   soup_uri_free (obj_uri);
 }
@@ -1619,6 +1621,14 @@ ostree_repo_pull_one_dir (OstreeRepo               *self,
                                         progress, cancellable, error);
 }
 
+static void
+pull_cancelled_cb (GCancellable *cancellable,
+                   OstreeFetcher *fetcher)
+{
+  /* Cancel all fetch requests. */
+  g_cancellable_cancel (_ostree_fetcher_get_cancellable (fetcher));
+}
+
 /* Documented in ostree-repo.c */
 gboolean
 ostree_repo_pull_with_options (OstreeRepo             *self,
@@ -1653,6 +1663,7 @@ ostree_repo_pull_with_options (OstreeRepo             *self,
   GSource *update_timeout = NULL;
   GSource *idle_src;
   gboolean disable_static_deltas = FALSE;
+  gulong cancellable_handler_id = 0;
 
   if (options)
     {
@@ -1732,6 +1743,14 @@ ostree_repo_pull_with_options (OstreeRepo             *self,
   requested_refs_to_fetch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
   commits_to_fetch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
+  if (cancellable != NULL)
+    {
+      cancellable_handler_id = g_cancellable_connect (cancellable,
+                                                      G_CALLBACK (pull_cancelled_cb),
+                                                      g_object_ref (pull_data->fetcher),
+                                                      (GDestroyNotify) g_object_unref);
+    }
+
   {
     g_autofree char *tls_client_cert_path = NULL;
     g_autofree char *tls_client_key_path = NULL;
@@ -2270,6 +2289,8 @@ ostree_repo_pull_with_options (OstreeRepo             *self,
     g_source_destroy (update_timeout);
   if (pull_data->loop)
     g_main_loop_unref (pull_data->loop);
+  if (cancellable_handler_id)
+    g_cancellable_disconnect (cancellable, cancellable_handler_id);
   g_strfreev (configured_branches);
   g_clear_object (&pull_data->fetcher);
   g_clear_object (&pull_data->remote_repo_local);
