waitForJob threw SumeJobTimeoutError: resume polling with the job id

The Sume SDK stops waiting after 20 minutes by default, but the job keeps running. Catch SumeJobTimeoutError, read jobId and wait again. TypeScript example.

4 min readSume
All posts

What do I do when waitForJob throws SumeJobTimeoutError?

Catch it, read error.jobId, and call waitForJob again for the same job. The error means your wait ran out, not that the job failed. The SDK's default timeout is 20 minutes, and a client-side timeout does not cancel the job: it keeps running and still bills.

Never resubmit on this error. A second submit creates a second paid job. If you lost the id as well, retry the original submit with the same Idempotency-Key: the replay returns the job you already created.

The 20 minute default exists because video and avatar jobs often run for minutes. If you know your clips are short, lower timeout so a stuck job surfaces sooner. If you submit long 30 second generations in a queue behind other work, raise it, or keep it and use the resume loop below, which gives you a log line and a decision point at each round.

What each error and result means

waitForJob resolves for any terminal status, including failed and canceled jobs. It throws only when the wait or the request itself fails.

waitForJob outcomes in @sume-com/sdk 0.2.0 (docs.sume.com, read 2026-10-06)
OutcomeMeaningNext step
Resolves, status completedResult readyRead job.result.artifacts
Resolves, status failed or canceledTerminal, not a throwRead the error, decide on a retry
Throws SumeJobTimeoutErrorWait ran out, job still runningWait again with error.jobId
Throws SumeJobRequestErrorThe API rejected a poll (401, 404, 5xx)Fix the key or id; it carries jobId

Resume the wait with a cap

Bound the number of resumes so a stuck job does not loop forever, and let next_poll_after_seconds set the pace: the SDK's pollInterval of 2 seconds is only a floor.

import { createSumeClient, waitForJob, SumeJobTimeoutError } from "@sume-com/sdk";

const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });

export async function finish(jobId: string, maxRounds = 3) {
  for (let round = 1; round <= maxRounds; round++) {
    try {
      return await waitForJob(jobId, { client, timeout: 20 * 60_000 });
    } catch (err) {
      if (!(err instanceof SumeJobTimeoutError)) throw err;
      console.log(`round ${round}: job ${err.jobId} still running`);
    }
  }
  throw new Error(`job ${jobId} still running; keep the id and check later`);
}

const job = await finish(process.argv[2]!);
console.log(job.status, job.result?.artifacts);

Store the id before you wait

Write the job id to your database as soon as the submit returns, before you call waitForJob. A process that restarts mid-wait can then resume instead of starting over. For work that can take many minutes, a webhook is a better primary path, with this loop as the fallback.

One more habit: pass an AbortSignal when your own process is shutting down. The SDK aborts the in-flight request and rejects with your reason, and the job is untouched on the Sume side, so the next process can resume it with the id you saved.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume