TypeScript 7: an exhaustive switch over Sume job statuses
Turn a Sume job record into done, failed, canceled or running with a never check, so a new status breaks the build. Compiled with tsc 7.0.2 in strict mode.

To handle every Sume job status safely in TypeScript, map the job record to a small discriminated union with a switch over status and assign the default branch to a never variable. The five documented statuses are queued, processing, completed, failed and canceled; if Sume adds a sixth and you widen your type, the compiler points at the one function that needs a new case. I compiled the 30-line version below with tsc 7.0.2, the current release on the npm registry on 2026-10-02, in strict mode.
This also fixes a common bug: treating anything that is not completed as failure. queued and processing are normal non-terminal states, and canceled is neither a success nor an error to retry.
Status to outcome
| Status | Terminal | Outcome in the code |
|---|---|---|
| queued | No | running |
| processing | No | running |
| completed | Yes | done, with artifact URLs |
| failed | Yes | failed, with code, message and retry flag |
| canceled | Yes | canceled |
The function
result and error are nullable on the job record, so the code reads them defensively: a completed job with no artifacts yields an empty list instead of throwing. The retryable flag comes from the job error metadata the errors page describes, and defaults to false when absent.
type Status = "queued" | "processing" | "completed" | "failed" | "canceled";
export type JobRecord = {
id: string;
status: Status;
result: { artifacts: { id: string; url: string }[] } | null;
error: { code: string; message: string; retryable?: boolean } | null;
};
export type Outcome =
| { kind: "done"; urls: string[] }
| { kind: "failed"; code: string; message: string; retry: boolean }
| { kind: "canceled" }
| { kind: "running"; status: "queued" | "processing" };
export function toOutcome(job: JobRecord): Outcome {
switch (job.status) {
case "completed":
return { kind: "done", urls: (job.result?.artifacts ?? []).map((a) => a.url) };
case "failed": {
const e = job.error;
return { kind: "failed", code: e?.code ?? "unknown", message: e?.message ?? "Job failed", retry: e?.retryable ?? false };
}
case "canceled": return { kind: "canceled" };
case "queued":
case "processing": return { kind: "running", status: job.status };
default: {
const unreachable: never = job.status; // a new status becomes a compile error
throw new Error(`unhandled status ${unreachable}`);
}
}
}Proof that the check works
Adding a sixth status to the Status type and recompiling gave Type '"paused"' is not assignable to type 'never' at the default branch. Running the compiled example through Node 22 with type stripping printed the artifact URL for a completed record and the error code for a failed one.
Keep your JobRecord type narrower than the real response. Describe only the fields you read, so an added field in the API never breaks your build, and only a changed status does.
Limits
The types here are hand-written from the documented job shape, not generated from the OpenAPI file; if you want generated types, @sume-com/sdk exports them for each operation, but check the version you install against the docs. Types do not validate runtime data. If a gateway or proxy hands you an HTML error page, job.status is undefined and the default branch throws, which is the behavior you want over silently treating it as running.
Sources
Related posts
More in Developers
- Bulk run says completed but UGC variants failed: read counts
A Sume bulk queue is completed once every item is terminal, not once every item succeeds. Read counts.failed and each item's status before shipping.
- One bad item in a 100-variant bulk run: 400 and nothing runs
A Sume bulk run checks every item before it creates the queue. One bad row returns 400 invalid_request with details.index, and none of the 100 videos start.
- Re-ran a UGC variant bulk run and got the old queue: why
Replaying a Sume bulk-run Idempotency-Key with the same body returns 202 and the existing queue, no new videos. A changed body is 409. Mint a key per batch.
- Veo 3.1 returns one video per request: how to get 4 variants
Google's Veo 3.1 table says one video per request. To get four variants on Sume, send four requests with four Idempotency-Keys, and watch queue_full.
Written by Sume