Errors & Retrying
Tasks retry automatically when an uncaught error is thrown. Configure retrying globally in trigger.config.ts or per task.
Task-Level Retry Config
ts
export const openaiTask = task({
id: "openai-task",
retry: {
maxAttempts: 10,
factor: 1.8,
minTimeoutInMs: 500,
maxTimeoutInMs: 30_000,
randomize: false,
},
run: async (payload: { prompt: string }) => {
const result = await openai.chat.completions.create({ /* ... */ });
return result.choices[0].message.content;
},
});retry.onThrow()
Retry a block of code within a task run:
ts
import { task, logger, retry } from "@trigger.dev/sdk";
export const retryOnThrow = task({
id: "retry-on-throw",
run: async (payload: any) => {
const result = await retry.onThrow(
async ({ attempt }) => {
if (attempt < 3) throw new Error("failed");
return { foo: "bar" };
},
{ maxAttempts: 3, randomize: false }
);
logger.info("Result", { result });
},
});retry.fetch()
HTTP requests with smart retry logic:
ts
// Retry on 429 using rate limit headers
const response = await retry.fetch("http://api.example.com/data", {
retry: {
byStatus: {
"429": {
strategy: "headers",
limitHeader: "x-ratelimit-limit",
remainingHeader: "x-ratelimit-remaining",
resetHeader: "x-ratelimit-reset",
resetFormat: "unix_timestamp_in_ms",
},
},
},
});
// Retry on 5xx with exponential backoff
const response2 = await retry.fetch("http://api.example.com/data", {
retry: {
byStatus: {
"500-599": {
strategy: "backoff",
maxAttempts: 10,
factor: 2,
minTimeoutInMs: 1_000,
maxTimeoutInMs: 30_000,
},
},
},
});
// With request timeout + retry on timeout
const response3 = await retry.fetch("https://api.example.com/slow", {
timeoutInMs: 1000,
retry: {
timeout: {
maxAttempts: 5,
factor: 1.8,
minTimeoutInMs: 500,
maxTimeoutInMs: 30_000,
},
},
});catchError — Advanced Error Handling
Override retry behavior per error type:
ts
export const openaiTask = task({
id: "openai-task",
catchError: async ({ payload, error, ctx, retryAt }) => {
if (error instanceof OpenAI.APIError) {
// No quota — don't retry
if (error.status === 429 && error.type === "insufficient_quota") {
return { skipRetrying: true };
}
// Rate limited — retry after reset
if (error.headers) {
const remaining = error.headers["x-ratelimit-remaining-requests"];
if (Number(remaining) === 0) {
return { retryAt: calculateResetAt(error.headers["x-ratelimit-reset-requests"]) };
}
}
}
// Default retry behavior for other errors
},
});Preventing Retries
AbortTaskRunError
Throw to permanently fail without retrying:
ts
import { task, AbortTaskRunError } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
run: async (payload) => {
if (someUnrecoverableCondition) {
throw new AbortTaskRunError("This run cannot be retried");
}
},
});try/catch — Fallback Strategy
Catch errors and use a fallback instead of retrying:
ts
run: async (payload) => {
try {
return await openai.chat.completions.create({ /* ... */ });
} catch (error) {
// Fallback to a different provider
return await replicate.run("meta/llama-2-70b-chat:...", {
input: { prompt: payload.prompt }
});
}
}