Sume SDK calls resolve with error: make your task throw
Generated Sume SDK operations return { data, error, response } and never throw. In Trigger.dev or Inngest, throw yourself or a failed run looks successful.

Generated @sume-com/sdk operations do not throw on an API error. They resolve with { data, error, response }, so a task that ignores error finishes as a success with an undefined job id, and a job runner never retries it.
Sume facts are from the SDK overview and Waiting for runs and jobs; the retry rule is from Trigger.dev's docs. Read 2026-10-01.
Which SDK calls throw and which do not?
The SDK docs say generated operations resolve with { data, error, response }, while subscribeFormatRun and waitForRun throw because a poll loop has nowhere to put a non-result. waitForJob throws SumeJobTimeoutError and SumeJobRequestError, both carrying jobId.
| Call | On failure |
|---|---|
Generated operations such as generateVideoV1 | Resolve with { data, error, response } |
subscribeFormatRun, waitForRun | Throw SumeRunRequestError or SumeRunTimeoutError |
waitForJob | Throws SumeJobTimeoutError or SumeJobRequestError |
Why does that matter inside a task runner?
Trigger.dev's docs say an uncaught thrown error triggers a retry per your config. A returned error object triggers nothing. A Sume 402 or 429 would end the run green and hand the next step an undefined id.
What is the minimal fix?
Check error right after the call and throw an Error that includes the response status. The idempotency header makes the retry that follows safe, because an exact retry returns the original job instead of billing twice.
import { createSumeClient, generateVideoV1 } from "@sume-com/sdk";
const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });
export async function submit(prompt: string, key: string) {
const { data, error, response } = await generateVideoV1({
client,
headers: { "idempotency-key": key },
body: { prompt, mode: "async" },
});
if (error || !data) {
throw new Error("sume " + response.status + " " + JSON.stringify(error));
}
return data.data.request_id;
}Should every error be retried?
No. Throwing hands the decision to the runner, which retries by default. Pair it with the skip rules in the Trigger.dev retry post so a 400 or 402 stops at once.
Sources
Related posts
More in Developers
- Supabase Edge Function 400 s wall clock vs a Sume video job
Supabase Edge Functions cap wall clock at 150 s on Free and 400 s on Paid. Do not wait on a video: submit in one function and receive the webhook in another.
- Supabase Edge Function secrets: 100 per project, 2 for Sume
Supabase allows 100 secrets per project. A Sume webhook receiver needs two: your API key and the webhook signing secret. Names, rules and what to verify.
- sync-3 image formats JPEG PNG WebP vs Sume image URL rules
sync-3 accepts JPEG, PNG and WebP stills. Sume's docs set URL rules instead: a fetchable public HTTPS image, with private and signed URLs rejected.
- sync-3 lip sync takes 10-15 min: async job and webhook pattern
Sync lists sync-3 at about 10-15 minutes for a 30 s video. Do not hold a request open: submit async, take a terminal webhook, and keep polling as a backup.
Written by Sume