Trigger.dev retries and Sume errors: skip 4xx, wait on retry-after
Trigger.dev retries any uncaught throw. Use catchError to skip Sume errors that cannot succeed, and read the retry-after header on a 429.

Trigger.dev retries a task whenever it throws, which is wrong for a Sume 400 or 402 that will fail the same way every time. Use catchError to skip those, and use the retry-after header on a 429, because Sume's rate-limit headers do not match the names in Trigger.dev's own retry.fetch example.
Trigger.dev facts are from its Errors and retrying docs; Sume facts from Errors and credits, Authentication and Generation admission, read 2026-10-01.
What does Trigger.dev do on an error?
The docs say an uncaught thrown error triggers a retry per your config. AbortTaskRunError disables retrying, retry.onThrow() retries a code block, and catchError can override the decision, for example by returning { skipRetrying: true }. The retry.fetch() example handles 429 with a headers strategy that reads x-ratelimit-limit, x-ratelimit-remaining and x-ratelimit-reset.
Which Sume errors should not retry?
Sume's 429 carries retry-after, ratelimit-limit, ratelimit-remaining and ratelimit-reset, with no x- prefix, and error.details.scope says read or write. Because the names differ, Trigger.dev's documented header example would not find them. Read retry-after yourself.
| Status and code | Meaning | Retry in the task |
|---|---|---|
400 invalid_request | Bad body or headers | No, fix the request |
401 unauthorized | Key missing or invalid | No |
402 insufficient_credits | Cannot reserve cost | No |
404 not_found | Unknown model or resource | No |
429 rate_limited | Request budget used | Yes, after retry-after |
429 queue_full | No accepted capacity left | Yes, later |
503 provider_capacity_exceeded | Cannot dispatch safely | Yes, check retryable |
How do you code the skip?
Throw a typed error that carries the HTTP status, and return skipRetrying for the codes that cannot succeed. Everything else keeps Trigger.dev's normal backoff.
import { task } from "@trigger.dev/sdk";
import { createSumeClient, generateVideoV1 } from "@sume-com/sdk";
class SumeHttpError extends Error {
constructor(public status: number, message: string) { super(message); }
}
const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });
export const submit = task({
id: "sume-submit",
retry: { maxAttempts: 5 },
run: async (p: { key: string; prompt: string }) => {
const { data, error, response } = await generateVideoV1({
client,
headers: { "idempotency-key": p.key },
body: { prompt: p.prompt, mode: "async" },
});
if (error) throw new SumeHttpError(response.status, JSON.stringify(error));
return data!.data.request_id;
},
catchError: async ({ error }) => {
const dead = [400, 401, 402, 404, 413, 415];
if (error instanceof SumeHttpError && dead.includes(error.status)) {
return { skipRetrying: true };
}
},
});Does the wait come from Trigger.dev or Sume?
Trigger.dev's backoff sets the spacing unless you sleep yourself, and retry-after is Sume's hint for how long that should be. A 429 means the budget for that scope is spent: writes are 120 a minute on Free up to 1,200 on Scale, and reads are forty times that. See the retry-after post.
Sources
Related posts
More in Developers
- Trigger.dev replay reuses the payload: key the Sume submit from it
A Trigger.dev replay starts a new run with the same payload. Derive the Sume Idempotency-Key from that payload, not a random id, or a replay bills twice.
- Turn a video into a line-art sketch by API with edgedetect
Sume's video filter allowlists edgedetect and negate. Edges come out as white wires on black; negating gives dark lines on white. Modes: wires, colormix, canny.
- Veo 3.1 latency is 11 seconds to 6 minutes: set your poll to match
Google lists Veo 3.1 request latency from 11 seconds to 6 minutes at peak. Poll with a deadline over 6 minutes; Sume's video docs poll every 30 seconds.
- Veo 3.1 videos are stored 2 days: download them, and what Sume does
Google says Veo videos are stored for 2 days, and referencing one for extension resets the timer. Save the file early; Sume jobs return Sume-hosted artifacts.
Written by Sume