Resume a Sume job wait after SumeJobTimeoutError in TypeScript

A 30-second Seedance 2.5 clip can outlast one waitForJob call. Call it again with the same job id on timeout or a transient read error. Never resubmit.

5 min readSume
All posts

When waitForJob throws SumeJobTimeoutError or a SumeJobRequestError for a transient read, the job is still running on Sume's side, so call waitForJob again with the same job id. Do not submit the request again, because that is a second paid job.

The wait helper has no built-in allowance for read failures, so a small loop around it is the whole recovery plan.

Which errors mean wait again?

The SDK retries GET reads inside the client first (two retries by default, with backoff), so an error that reaches you has already been tried more than once. Decide by class and status.

waitForJob errors (@sume-com/sdk 0.2.0 source and README, read 2026-10-09)
OutcomeCarriesNext step
ResolvesThe job record, for completed, failed or canceledRead status and error; a failed job is a result, not an exception
SumeJobTimeoutErrorjobId, lastStatusWait again with the same id
SumeJobRequestError, status 429 or 5xxjobId, status, bodyWait again after a pause
SumeJobRequestError, status 401, 403 or 404jobId, status, bodyStop and fix the key or the id

What does the loop look like?

Cap the number of rounds so a broken key cannot spin forever. Each round is its own deadline, so ten minutes per round gives a 30-second Seedance 2.5 clip plenty of time.

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

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

async function settle(jobId: string, rounds = 3) {
  for (let i = 1; i <= rounds; i++) {
    try {
      return await waitForJob(jobId, { client, timeout: 10 * 60_000 });
    } catch (e) {
      const transient =
        e instanceof SumeJobTimeoutError ||
        (e instanceof SumeJobRequestError &&
          (e.status === undefined || e.status === 429 || e.status >= 500));
      if (!transient || i === rounds) throw e;
      console.warn(`round ${i} ended early; waiting again for ${jobId}`);
    }
  }
}

const job = await settle(process.env.JOB_ID!);
console.log(job?.status, job?.error ?? "no error");

What should I do after the last round?

Keep the job id in your own store and stop. The job record, the status endpoint and the events endpoint all stay readable, so a later run can pick up the same id. If you registered a webhook, the terminal event will also arrive on its own, and it is the better trigger than a long-lived process.

Why not raise the timeout instead?

You can, since the default is 20 minutes and the option takes milliseconds. A loop gives you one more thing, a log line and a decision point between rounds, and it survives a single dropped connection that a long single wait would not, once the client's own retries are used up.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume