Skip to content

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 }
    });
  }
}

Built from official Trigger.dev documentation