Sume uploadFile with raw bytes needs a content type, or no request
uploadFile refuses a Uint8Array or ArrayBuffer without contentType and throws SumeUploadError at step create before any call. Pass a typed Blob or a MIME.

If uploadFile from @sume-com/sdk throws contentType is required unless file is a Blob with a type, you passed raw bytes with no MIME type, and nothing was sent. The helper does not guess the type from the filename or from magic bytes. The error is a SumeUploadError with step set to create and status undefined, because no HTTP response exists yet.
Fix it in one of two ways: pass contentType explicitly, or pass a Blob or File whose type is non-empty. A blank or whitespace-only contentType counts as missing, and an explicit value wins over the Blob type.
Which input carries a type
The helper accepts a Blob, an ArrayBuffer or a Uint8Array. Only a Blob can bring its own type. The upload is the first of three calls described in the asset flow: reserve a URL, PUT the bytes, then complete.
| Input | contentType option | Result |
|---|---|---|
| Uint8Array or ArrayBuffer | missing | Throws at step create, no request |
| Uint8Array or ArrayBuffer | image/png | Used as given |
| Blob with type | missing | Blob type used |
| Blob with empty type | missing | Throws at step create, no request |
| Blob with type | video/mp4 | Option wins |
Seeing the guard fire
This script needs no network. The client is built with a placeholder key because the guard throws before the client is used, so you can run it in a unit test.
import { createSumeClient, uploadFile, SumeUploadError } from "@sume-com/sdk";
const client = createSumeClient({ apiKey: "test-key" });
const bytes = new Uint8Array([137, 80, 78, 71]);
try {
await uploadFile({ client, file: bytes });
} catch (error) {
if (error instanceof SumeUploadError) {
console.log(error.step, error.status, error.message);
} else {
throw error;
}
}
// With a type the call proceeds to the network, so pass a real key to run it.
// await uploadFile({ client, file: bytes, contentType: "image/png" });What to do in an upload service
- Take the MIME type from the user-facing upload, such as the multipart part header, and pass it through. Validate it against an allowlist first.
- Do not retry a step create failure with the same arguments. It is deterministic.
- Branch on
error.stepin logs so a missing type is not confused with a storage failure at put. - Check the returned
content_typeagainst what you sent when the type matters downstream.
Related posts
More in Developers
- Patching Supabase Postgres 17.11 vs Sume's 10-attempt webhook budget
Supabase's September 25 Postgres 15.19 and 17.11 releases fix 44 CVEs. A restart can outlast Sume's ten 30-second webhook attempts, so plan a redeliver.
- Supabase cached egress is $0.03/GB: cost of serving a 20 MB AI clip
Supabase lists cached Storage egress at $0.03 per GB. Worked arithmetic for serving generated clips, and when to link a Sume media URL instead of copying.
- End-user id on jobs: OpenAI safety identifier vs Sume metadata
OpenAI's Realtime guide asks for an OpenAI-Safety-Identifier header. Sume stores caller metadata on the job but does not send it to the provider. Use both.
- Temporal Paygo starter: submit and poll a Sume job
Temporal's Paygo plan has a $0 monthly minimum. A first workflow can submit a Sume job in one Activity and poll its status in a second. Python code included.
Written by Sume