waitForJob on a failed Sume image job: read the record, skip /result
waitForJob resolves for failed and canceled jobs instead of throwing, and /result returns 409 job_not_completed for them. How to branch on job.status.

In @sume-com/sdk, waitForJob resolves with the terminal job for any terminal status, not just completed. The SDK source explains why: it reads /v1/jobs/{id} for the final hop, because GET /v1/jobs/{id}/result answers 409 job_not_completed for failed and canceled jobs, and there would be nothing to hand back.
So a failed Ideogram or gpt-image-2.5 job is a result you asked for, not an exception. Branch on job.status, exactly as a webhook handler would.
Branch on the status
import { createSumeClient, waitForJob } from "@sume-com/sdk";
const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });
export async function finish(jobId: string) {
// Resolves for completed, failed and canceled. It throws only on timeout or a read error.
const job = await waitForJob(jobId, { client, timeout: 5 * 60_000 });
switch (job.status) {
case "completed":
return { ok: true as const, job };
case "failed":
return { ok: false as const, reason: job.error }; // not GET /result: that is a 409
case "canceled":
return { ok: false as const, reason: "canceled" };
default:
throw new Error(`unexpected non-terminal status ${job.status}`);
}
}What does throw
| Situation | What you get |
|---|---|
| completed | Resolved job |
| failed or canceled | Resolved job with status and error |
| timeout before a terminal status | SumeJobTimeoutError with jobId and lastStatus |
| status read fails with an API error | SumeJobRequestError with status and body |
Habits that follow
- Do not call
/resulton a job you have not confirmedcompleted; it is for finished output only. - On a timeout the job is still running and billable. Keep
jobIdand resume instead of resubmitting. - A failed generation is not billed, but log the error object so you can tell a bad prompt from a provider fault.
Sources
Related posts
More in Developers
- Webhook for an unknown job_id: park it, then reconcile on insert
A Sume job.completed webhook can name a job_id your database has not stored yet. Return 2xx, park the event in SQLite, and apply it when the insert lands.
- Sume TTS source errors: which are safe to retry (status table)
Every tts_ error code in Sume's script-source API with its HTTP status, whether it charges, and whether a retry can help. A table for client error handling.
- Word timestamps to video frame numbers at 29.97 fps in Python
Sume STT words[] carry start and end in seconds. Convert them to frame indexes with exact 30000/1001 math so cuts do not drift on long timelines.
- Zed context_servers for the hosted Sume server: no header means OAuth
Add the hosted Sume server to Zed's settings.json context_servers with a url. With no Authorization header Zed runs the MCP OAuth flow, so start with mcp:read.
Written by Sume