waitForJob timeout in the Sume TypeScript SDK: keep the job id
waitForJob waits 20 minutes by default and throws SumeJobTimeoutError without cancelling the render. Catch it, store jobId, and resume later. Sume SDK 0.2.0.

waitForJob in @sume-com/sdk@0.2.0 waits up to 20 minutes by default, and when that runs out it throws SumeJobTimeoutError without cancelling anything. Catch the error, store error.jobId, and read the job again later, because the render keeps running and keeps billing.
The helper is a client-side wait, so it can outlast the 30-second cap on the server-side sync and subscribe modes. That cap is a budget for the HTTP request, not for the job.
Defaults to know
The poll interval is 2 seconds, but it is a floor: when the status payload has a larger next_poll_after_seconds, that value wins. onStatus is called on every status read including the terminal one, and signal aborts both the wait and the request in flight.
| Option | Default | Note |
|---|---|---|
| timeout | 20 minutes | Throws SumeJobTimeoutError |
| pollInterval | 2 seconds | A floor; next_poll_after_seconds can raise it |
| signal | none | Aborts the wait and the in-flight request |
| onStatus | none | Called on every read, terminal included |
| client | module default | Pass your own; the default has no key |
Catching the timeout
The submit below is the documented example from the SDK page. The point is the catch: a timeout is not a failure of the job, so log the id and exit cleanly. A failed or canceled job resolves instead of throwing, so read status, result and error from the returned record.
import {
createSumeClient, generateVideoV1, waitForJob, SumeJobTimeoutError,
} from "@sume-com/sdk";
const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });
const { data: submitted, error } = await generateVideoV1({
client,
headers: { "idempotency-key": crypto.randomUUID() },
body: { prompt: "Slow push-in on a ceramic mug", mode: "async" },
});
if (error) throw new Error(JSON.stringify(error));
try {
const job = await waitForJob(submitted!.data.request_id, {
client,
timeout: 5 * 60_000,
onStatus: (status) => console.log(status),
});
console.log(job.status, job.result);
} catch (e) {
if (e instanceof SumeJobTimeoutError) {
console.error("still running, resume with job id", e.jobId);
process.exitCode = 2;
} else throw e;
}Resuming
The docs name getApiJob for reading the job again and cancelApiJob for cancelling it, so store the id somewhere durable before you exit. Cancel works only before generation starts, so for a render already running the useful move is to read it later, not to cancel it.
If you cannot hold a process open for a long render, skip the wait: pass a webhook URL on submit and let the terminal event arrive. Keep a short poll as a reconcile fallback for deliveries you miss.
Why a shorter timeout can be right
- A worker with a hard deadline should time out early and resume, rather than hold a slot.
- A serverless function should wait far less than its own limit.
- The timeout never saves money; only a cancel before start does.
Two surfaces, two helpers
Runs and jobs are different. Format, Action and Agent runs use waitForRun and subscribeFormatRun, with a 10 or 20 minute default. Generation jobs, which have ids that start at /v1/jobs/:id, use waitForJob. Passing a job id to the run helper, or the reverse, will not work, because they live behind different URL prefixes.
The practical rule for a 30-second render is to set your own timeout. The default of 20 minutes is long for an HTTP handler and short enough for a worker. Pick the number from where the code runs, not from the model.
Wiring it into a worker
In a queue worker, treat the timeout as a normal outcome. Write the job id to your own table, mark the task as waiting, and let a later task resume it. Throwing the error away would lose the id, and with it the render you already paid for.
Exit code 2 in the example is a convention, not a Sume value. Use whatever your scheduler reads as retry later.
Sources
Related posts
More in Developers
- Wan 3.0 for 30 seconds in Node: submit, poll, save the MP4
A runnable Node 18+ script for Sume's /v1/videos: submit wan-3.0 at 30 seconds, poll with a deadline, stream the MP4 to disk. Price: $1.88 at 480p.
- Wan 3.0 on Alibaba: 300 requests a minute across all regions, planned
Alibaba caps Wan 3.0 at 300 requests per minute across all six regions, so a region switch does not add headroom. How to plan a batch of 30 s jobs.
- Wan 3.0 and Seedance 2.5 auto duration on fal: send seconds on Sume
fal lets Wan 3 pick its own length and Seedance 2.5 accepts auto. On Sume, send an integer duration so the price is known before you submit.
- Wan 3.0 on Sume: one id, three modes, and which field picks each
fal lists three Wan 3 endpoints. Sume has one id, wan-3.0, and picks text, image or reference-to-video from frame_images and input_references.
Written by Sume