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.

5 min readSume
All posts

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.

waitForJob options and defaults, Sume SDK docs read 2026-10-05
OptionDefaultNote
timeout20 minutesThrows SumeJobTimeoutError
pollInterval2 secondsA floor; next_poll_after_seconds can raise it
signalnoneAborts the wait and the in-flight request
onStatusnoneCalled on every read, terminal included
clientmodule defaultPass 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

All Developers posts

Written by Sume