diff --git a/keyserver/src/push/crypto.js b/keyserver/src/push/crypto.js
--- a/keyserver/src/push/crypto.js
+++ b/keyserver/src/push/crypto.js
@@ -1,9 +1,12 @@
 // @flow
 
 import apn from '@parse/node-apn';
+import crypto from 'crypto';
 import invariant from 'invariant';
 import _cloneDeep from 'lodash/fp/cloneDeep.js';
 
+import { toBase64URL } from 'lib/utils/base64.js';
+
 import type {
   AndroidNotification,
   AndroidNotificationPayload,
@@ -11,6 +14,7 @@
   NotificationTargetDevice,
 } from './types.js';
 import { encryptAndUpdateOlmSession } from '../updaters/olm-session-updater.js';
+import { encrypt, generateKey } from '../utils/aes-crypto-utils.js';
 import { getOlmUtility } from '../utils/olm-utils.js';
 
 async function encryptIOSNotification(
@@ -312,9 +316,36 @@
   return Promise.all(notificationPromises);
 }
 
+async function encryptBlobPayload(payload: string): Promise<{
+  +encryptionKey: string,
+  +encryptedPayload: Blob,
+  +encryptedPayloadHash: string,
+}> {
+  const encryptionKey = await generateKey();
+  const encryptedPayload = await encrypt(
+    encryptionKey,
+    new TextEncoder().encode(payload),
+  );
+  const encryptedPayloadBuffer = Buffer.from(encryptedPayload);
+  const blobHashBase64 = await crypto
+    .createHash('sha256')
+    .update(encryptedPayloadBuffer)
+    .digest('base64');
+  const blobHash = toBase64URL(blobHashBase64);
+
+  const payloadBlob = new Blob([encryptedPayloadBuffer]);
+  const encryptionKeyString = Buffer.from(encryptionKey).toString('base64');
+  return {
+    encryptionKey: encryptionKeyString,
+    encryptedPayload: payloadBlob,
+    encryptedPayloadHash: blobHash,
+  };
+}
+
 export {
   prepareEncryptedIOSNotifications,
   prepareEncryptedIOSNotificationRescind,
   prepareEncryptedAndroidNotifications,
   prepareEncryptedAndroidNotificationRescinds,
+  encryptBlobPayload,
 };
diff --git a/keyserver/src/push/utils.js b/keyserver/src/push/utils.js
--- a/keyserver/src/push/utils.js
+++ b/keyserver/src/push/utils.js
@@ -5,6 +5,7 @@
 import invariant from 'invariant';
 import nodeFetch from 'node-fetch';
 import type { Response } from 'node-fetch';
+import uuid from 'uuid';
 import webpush from 'web-push';
 
 import type { PlatformDetails } from 'lib/types/device-types.js';
@@ -15,6 +16,7 @@
 import { threadSubscriptions } from 'lib/types/subscription-types.js';
 import { threadPermissions } from 'lib/types/thread-permission-types.js';
 
+import { encryptBlobPayload } from './crypto.js';
 import {
   getAPNPushProfileForCodeVersion,
   getFCMPushProfileForCodeVersion,
@@ -385,7 +387,20 @@
     }
   | { +blobUploadError: string },
 > {
-  return upload(payload);
+  const blobHolder = uuid.v4();
+  try {
+    const { encryptionKey, encryptedPayload, encryptedPayloadHash } =
+      await encryptBlobPayload(payload);
+    await upload(encryptedPayload, encryptedPayloadHash, blobHolder);
+    return {
+      blobHash: encryptedPayloadHash,
+      encryptionKey,
+    };
+  } catch (e) {
+    return {
+      blobUploadError: e.message,
+    };
+  }
 }
 
 export {
diff --git a/keyserver/src/services/blob.js b/keyserver/src/services/blob.js
--- a/keyserver/src/services/blob.js
+++ b/keyserver/src/services/blob.js
@@ -1,48 +1,21 @@
 // @flow
 
-import crypto from 'crypto';
-import uuid from 'uuid';
-
 import blobService from 'lib/facts/blob-service.js';
-import { toBase64URL } from 'lib/utils/base64.js';
 import { makeBlobServiceEndpointURL } from 'lib/utils/blob-service.js';
 import { getMessageForException } from 'lib/utils/errors.js';
 
-import { encrypt, generateKey } from '../utils/aes-crypto-utils.js';
-
-async function upload(payload: string): Promise<
-  | {
-      +blobHash: string,
-      +encryptionKey: string,
-    }
-  | { +blobUploadError: string },
-> {
-  const encryptionKey = await generateKey();
-  const encryptedPayloadBuffer = Buffer.from(
-    await encrypt(encryptionKey, new TextEncoder().encode(payload)),
-  );
-
-  const blobHolder = uuid.v4();
-  const blobHashBase64 = await crypto
-    .createHash('sha256')
-    .update(encryptedPayloadBuffer)
-    .digest('base64');
-
-  const blobHash = toBase64URL(blobHashBase64);
-
+async function upload(blob: Blob, hash: string, holder: string): Promise<void> {
   const formData = new FormData();
-  const payloadBlob = new Blob([encryptedPayloadBuffer]);
-
-  formData.append('blob_hash', blobHash);
-  formData.append('blob_data', payloadBlob);
+  formData.append('blob_hash', hash);
+  formData.append('blob_data', blob);
 
   const assignHolderPromise = fetch(
     makeBlobServiceEndpointURL(blobService.httpEndpoints.ASSIGN_HOLDER),
     {
       method: blobService.httpEndpoints.ASSIGN_HOLDER.method,
       body: JSON.stringify({
-        holder: blobHolder,
-        blob_hash: blobHash,
+        holder,
+        blob_hash: hash,
       }),
       headers: {
         'content-type': 'application/json',
@@ -58,38 +31,31 @@
     },
   );
 
+  let assignHolderResponse, uploadBlobResponse;
   try {
-    const [assignHolderResponse, uploadBlobResponse] = await Promise.all([
+    [assignHolderResponse, uploadBlobResponse] = await Promise.all([
       assignHolderPromise,
       uploadHolderPromise,
     ]);
-
-    if (!assignHolderResponse.ok) {
-      const { status, statusText } = assignHolderResponse;
-      return {
-        blobUploadError: `Holder assignment failed with HTTP ${status}: ${statusText}`,
-      };
-    }
-
-    if (!uploadBlobResponse.ok) {
-      const { status, statusText } = uploadBlobResponse;
-      return {
-        blobUploadError: `Payload upload failed with HTTP ${status}: ${statusText}`,
-      };
-    }
   } catch (e) {
-    return {
-      blobUploadError: `Payload upload failed with: ${
+    throw new Error(
+      `Payload upload failed with: ${
         getMessageForException(e) ?? 'unknown error'
       }`,
-    };
+    );
   }
 
-  const encryptionKeyString = Buffer.from(encryptionKey).toString('base64');
-  return {
-    blobHash,
-    encryptionKey: encryptionKeyString,
-  };
+  if (!assignHolderResponse.ok) {
+    const { status, statusText } = assignHolderResponse;
+    throw new Error(
+      `Holder assignment failed with HTTP ${status}: ${statusText}`,
+    );
+  }
+
+  if (!uploadBlobResponse.ok) {
+    const { status, statusText } = uploadBlobResponse;
+    throw new Error(`Payload upload failed with HTTP ${status}: ${statusText}`);
+  }
 }
 
 export { upload };