From 995c3f49a0873dbc35d25e5fb40f2ecf01e46a28 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 6 May 2026 16:36:58 +0100 Subject: [PATCH 1/8] feat(core): add maxComputeSeconds, deprecate maxDuration in user-facing types --- packages/core/src/v3/config.ts | 14 +++++++++++++- packages/core/src/v3/types/tasks.ts | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/core/src/v3/config.ts b/packages/core/src/v3/config.ts index 40334f04280..efa9c841386 100644 --- a/packages/core/src/v3/config.ts +++ b/packages/core/src/v3/config.ts @@ -165,6 +165,17 @@ export type TriggerConfig = { */ logLevel?: LogLevel; + /** + * The maximum duration in compute-time **seconds** that a task run is allowed to run. If the task run exceeds this duration, it will be stopped. + * + * Minimum value is 5 seconds. + * + * Setting this value will affect all tasks in the project. You can override it on a per-task basis. + * + * @see https://trigger.dev/docs/tasks/overview#maxcomputeseconds-option + */ + maxComputeSeconds?: number; + /** * The maximum duration in compute-time seconds that a task run is allowed to run. If the task run exceeds this duration, it will be stopped. * @@ -172,9 +183,10 @@ export type TriggerConfig = { * * Setting this value will effect all tasks in the project. * + * @deprecated Use `maxComputeSeconds` instead — same semantics, clearer unit. If both are set, `maxComputeSeconds` wins. * @see https://trigger.dev/docs/tasks/overview#maxduration-option */ - maxDuration: number; + maxDuration?: number; /** * Set a default time-to-live (TTL) for all task runs in the project. If a run is not executed within this time, it will be removed from the queue and never execute. diff --git a/packages/core/src/v3/types/tasks.ts b/packages/core/src/v3/types/tasks.ts index d04d088ef1a..8a29b8f5308 100644 --- a/packages/core/src/v3/types/tasks.ts +++ b/packages/core/src/v3/types/tasks.ts @@ -271,10 +271,19 @@ type CommonTaskOptions< } | MachinePresetName; + /** + * The maximum duration in compute-time **seconds** that a task run is allowed to run. If the task run exceeds this duration, it will be stopped. + * + * Minimum value is 5 seconds. + */ + maxComputeSeconds?: number; + /** * The maximum duration in compute-time seconds that a task run is allowed to run. If the task run exceeds this duration, it will be stopped. * * Minimum value is 5 seconds + * + * @deprecated Use `maxComputeSeconds` instead — same semantics, clearer unit. If both are set, `maxComputeSeconds` wins. */ maxDuration?: number; @@ -876,12 +885,23 @@ export type TriggerOptions = { */ metadata?: Record; + /** + * The maximum duration in compute-time **seconds** that a task run is allowed to run. If the task run exceeds this duration, it will be stopped. + * + * This will override the task's `maxComputeSeconds` (or the legacy `maxDuration`). + * + * Minimum value is 5 seconds. + */ + maxComputeSeconds?: number; + /** * The maximum duration in compute-time seconds that a task run is allowed to run. If the task run exceeds this duration, it will be stopped. * * This will override the task's maxDuration. * * Minimum value is 5 seconds + * + * @deprecated Use `maxComputeSeconds` instead — same semantics, clearer unit. If both are set, `maxComputeSeconds` wins. */ maxDuration?: number; From 15a36bf659150de357d26595b4c6f404e05c2ee7 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 6 May 2026 16:38:08 +0100 Subject: [PATCH 2/8] feat(sdk): resolve maxComputeSeconds at user-facing boundaries - defineConfig: resolves maxComputeSeconds ?? maxDuration into maxDuration - new resolveMaxComputeSeconds helper for shared.ts - task definitions, trigger and batchTrigger options funnel through helper Internal references to maxDuration (run engine, queues, DB) are unchanged. --- packages/trigger-sdk/src/v3/config.ts | 10 +++++- .../trigger-sdk/src/v3/maxComputeSeconds.ts | 13 ++++++++ packages/trigger-sdk/src/v3/shared.ts | 33 ++++++++++--------- 3 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 packages/trigger-sdk/src/v3/maxComputeSeconds.ts diff --git a/packages/trigger-sdk/src/v3/config.ts b/packages/trigger-sdk/src/v3/config.ts index 3bf32ac6670..39d62985628 100644 --- a/packages/trigger-sdk/src/v3/config.ts +++ b/packages/trigger-sdk/src/v3/config.ts @@ -9,7 +9,15 @@ export type { } from "@trigger.dev/core/v3"; export function defineConfig(config: TriggerConfig): TriggerConfig { - return config; + // `maxComputeSeconds` is the new name for `maxDuration`. If both are set, the new + // name wins. Internally the SDK and platform still read `maxDuration`, so we + // collapse the two fields here at the user-facing boundary. + const { maxComputeSeconds, maxDuration, ...rest } = config; + const resolved = maxComputeSeconds ?? maxDuration; + return { + ...rest, + ...(resolved !== undefined ? { maxDuration: resolved } : {}), + }; } export type { TriggerConfig }; diff --git a/packages/trigger-sdk/src/v3/maxComputeSeconds.ts b/packages/trigger-sdk/src/v3/maxComputeSeconds.ts new file mode 100644 index 00000000000..d2045d4eeb3 --- /dev/null +++ b/packages/trigger-sdk/src/v3/maxComputeSeconds.ts @@ -0,0 +1,13 @@ +/** + * Collapse the user-facing `maxComputeSeconds` (new name) and `maxDuration` (deprecated) + * into a single value. If both are provided, `maxComputeSeconds` wins. + * + * Internal SDK/CLI/platform code only reads `maxDuration`, so all call sites that + * accept user input should funnel through this helper before forwarding the value. + */ +export function resolveMaxComputeSeconds(input: { + maxComputeSeconds?: number; + maxDuration?: number; +}): number | undefined { + return input.maxComputeSeconds ?? input.maxDuration; +} diff --git a/packages/trigger-sdk/src/v3/shared.ts b/packages/trigger-sdk/src/v3/shared.ts index c69bceeb535..cce0a034352 100644 --- a/packages/trigger-sdk/src/v3/shared.ts +++ b/packages/trigger-sdk/src/v3/shared.ts @@ -31,6 +31,7 @@ import { TaskRunExecutionResult, TaskRunPromise, } from "@trigger.dev/core/v3"; +import { resolveMaxComputeSeconds } from "./maxComputeSeconds.js"; import { tracer } from "./tracer.js"; import type { @@ -235,7 +236,7 @@ export function createTask< queue: params.queue, retry: params.retry ? { ...defaultRetryOptions, ...params.retry } : undefined, machine: typeof params.machine === "string" ? { preset: params.machine } : params.machine, - maxDuration: params.maxDuration, + maxDuration: resolveMaxComputeSeconds(params), ttl: params.ttl, payloadSchema: params.jsonSchema, fns: { @@ -367,7 +368,7 @@ export function createSchemaTask< queue: params.queue, retry: params.retry ? { ...defaultRetryOptions, ...params.retry } : undefined, machine: typeof params.machine === "string" ? { preset: params.machine } : params.machine, - maxDuration: params.maxDuration, + maxDuration: resolveMaxComputeSeconds(params), ttl: params.ttl, fns: { run: params.run, @@ -643,7 +644,7 @@ export async function batchTriggerById( tags: item.options?.tags, maxAttempts: item.options?.maxAttempts, metadata: item.options?.metadata, - maxDuration: item.options?.maxDuration, + maxDuration: item.options ? resolveMaxComputeSeconds(item.options) : undefined, idempotencyKey: (await makeIdempotencyKey(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey, idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL, @@ -900,7 +901,7 @@ export async function batchTriggerByIdAndWait( tags: item.options?.tags, maxAttempts: item.options?.maxAttempts, metadata: item.options?.metadata, - maxDuration: item.options?.maxDuration, + maxDuration: item.options ? resolveMaxComputeSeconds(item.options) : undefined, idempotencyKey: (await makeIdempotencyKey(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey, idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL, @@ -1159,7 +1160,7 @@ export async function batchTriggerTasks( tags: item.options?.tags, maxAttempts: item.options?.maxAttempts, metadata: item.options?.metadata, - maxDuration: item.options?.maxDuration, + maxDuration: item.options ? resolveMaxComputeSeconds(item.options) : undefined, idempotencyKey: (await makeIdempotencyKey(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey, idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL, @@ -1421,7 +1422,7 @@ export async function batchTriggerAndWaitTasks( tags: item.options?.tags, maxAttempts: item.options?.maxAttempts, metadata: item.options?.metadata, - maxDuration: item.options?.maxDuration, + maxDuration: item.options ? resolveMaxComputeSeconds(item.options) : undefined, idempotencyKey: (await makeIdempotencyKey(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey, idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL, @@ -1876,7 +1877,7 @@ async function* transformBatchItemsStreamForWait( tags: item.options?.tags, maxAttempts: item.options?.maxAttempts, metadata: item.options?.metadata, - maxDuration: item.options?.maxDuration, + maxDuration: item.options ? resolveMaxComputeSeconds(item.options) : undefined, idempotencyKey: (await makeIdempotencyKey(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey, idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL, @@ -1926,7 +1927,7 @@ async function* transformBatchByTaskItemsStream( tags: item.options?.tags, maxAttempts: item.options?.maxAttempts, metadata: item.options?.metadata, - maxDuration: item.options?.maxDuration, + maxDuration: item.options ? resolveMaxComputeSeconds(item.options) : undefined, idempotencyKey: (await makeIdempotencyKey(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey, idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL, @@ -2091,7 +2092,7 @@ async function* transformSingleTaskBatchItemsStreamForWait( tags: item.options?.tags, maxAttempts: item.options?.maxAttempts, metadata: item.options?.metadata, - maxDuration: item.options?.maxDuration, + maxDuration: item.options ? resolveMaxComputeSeconds(item.options) : undefined, idempotencyKey: finalIdempotencyKey?.toString(), idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL, idempotencyKeyOptions, @@ -2141,7 +2142,7 @@ async function trigger_internal( tags: options?.tags, maxAttempts: options?.maxAttempts, metadata: options?.metadata, - maxDuration: options?.maxDuration, + maxDuration: options ? resolveMaxComputeSeconds(options) : undefined, parentRunId: taskContext.ctx?.run.id, machine: options?.machine, priority: options?.priority, @@ -2225,7 +2226,7 @@ async function batchTrigger_internal( tags: item.options?.tags, maxAttempts: item.options?.maxAttempts, metadata: item.options?.metadata, - maxDuration: item.options?.maxDuration, + maxDuration: item.options ? resolveMaxComputeSeconds(item.options) : undefined, idempotencyKey: finalIdempotencyKey?.toString(), idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL, idempotencyKeyOptions, @@ -2398,7 +2399,7 @@ async function triggerAndWait_internal Date: Wed, 6 May 2026 16:38:43 +0100 Subject: [PATCH 3/8] test(sdk): cover maxComputeSeconds precedence in defineConfig and helper --- packages/trigger-sdk/src/v3/config.test.ts | 29 +++++++++++++++++++ .../src/v3/maxComputeSeconds.test.ts | 20 +++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 packages/trigger-sdk/src/v3/config.test.ts create mode 100644 packages/trigger-sdk/src/v3/maxComputeSeconds.test.ts diff --git a/packages/trigger-sdk/src/v3/config.test.ts b/packages/trigger-sdk/src/v3/config.test.ts new file mode 100644 index 00000000000..fb2b4289d8c --- /dev/null +++ b/packages/trigger-sdk/src/v3/config.test.ts @@ -0,0 +1,29 @@ +import { describe, it, expect } from "vitest"; +import { defineConfig } from "./config.js"; + +describe("defineConfig - maxComputeSeconds", () => { + it("uses maxComputeSeconds when only maxComputeSeconds is set", () => { + const cfg = defineConfig({ project: "p", maxComputeSeconds: 600 }); + expect(cfg.maxDuration).toBe(600); + }); + + it("uses maxDuration when only maxDuration is set", () => { + const cfg = defineConfig({ project: "p", maxDuration: 600 }); + expect(cfg.maxDuration).toBe(600); + }); + + it("prefers maxComputeSeconds when both are set", () => { + const cfg = defineConfig({ project: "p", maxComputeSeconds: 600, maxDuration: 9999 }); + expect(cfg.maxDuration).toBe(600); + }); + + it("leaves maxDuration unset when neither is provided", () => { + const cfg = defineConfig({ project: "p" }); + expect(cfg.maxDuration).toBeUndefined(); + }); + + it("strips maxComputeSeconds from the returned config", () => { + const cfg = defineConfig({ project: "p", maxComputeSeconds: 600 }); + expect((cfg as { maxComputeSeconds?: number }).maxComputeSeconds).toBeUndefined(); + }); +}); diff --git a/packages/trigger-sdk/src/v3/maxComputeSeconds.test.ts b/packages/trigger-sdk/src/v3/maxComputeSeconds.test.ts new file mode 100644 index 00000000000..6898a16610a --- /dev/null +++ b/packages/trigger-sdk/src/v3/maxComputeSeconds.test.ts @@ -0,0 +1,20 @@ +import { describe, it, expect } from "vitest"; +import { resolveMaxComputeSeconds } from "./maxComputeSeconds.js"; + +describe("resolveMaxComputeSeconds", () => { + it("returns maxComputeSeconds when only maxComputeSeconds is set", () => { + expect(resolveMaxComputeSeconds({ maxComputeSeconds: 300 })).toBe(300); + }); + + it("returns maxDuration when only maxDuration is set", () => { + expect(resolveMaxComputeSeconds({ maxDuration: 300 })).toBe(300); + }); + + it("prefers maxComputeSeconds when both are set", () => { + expect(resolveMaxComputeSeconds({ maxComputeSeconds: 300, maxDuration: 999 })).toBe(300); + }); + + it("returns undefined when neither is set", () => { + expect(resolveMaxComputeSeconds({})).toBeUndefined(); + }); +}); From 328a3484bf1f0a22c7905e414886671571d4eff9 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 6 May 2026 16:39:31 +0100 Subject: [PATCH 4/8] feat(cli): use maxComputeSeconds in init templates --- packages/cli-v3/templates/examples/schedule.mjs.template | 4 ++-- packages/cli-v3/templates/examples/schedule.ts.template | 4 ++-- packages/cli-v3/templates/examples/simple.mjs.template | 4 ++-- packages/cli-v3/templates/examples/simple.ts.template | 4 ++-- packages/cli-v3/templates/trigger.config.mjs.template | 4 ++-- packages/cli-v3/templates/trigger.config.ts.template | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/cli-v3/templates/examples/schedule.mjs.template b/packages/cli-v3/templates/examples/schedule.mjs.template index 5622b37a91e..56b7fafd74d 100644 --- a/packages/cli-v3/templates/examples/schedule.mjs.template +++ b/packages/cli-v3/templates/examples/schedule.mjs.template @@ -4,8 +4,8 @@ export const firstScheduledTask = schedules.task({ id: "first-scheduled-task", // Every hour cron: "0 * * * *", - // Set an optional maxDuration to prevent tasks from running indefinitely - maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute + // Set an optional maxComputeSeconds to prevent tasks from running indefinitely + maxComputeSeconds: 300, // Stop executing after 300 secs (5 mins) of compute run: async (payload, { ctx }) => { // The payload contains the last run timestamp that you can use to check if this is the first run // And calculate the time since the last run diff --git a/packages/cli-v3/templates/examples/schedule.ts.template b/packages/cli-v3/templates/examples/schedule.ts.template index 5622b37a91e..56b7fafd74d 100644 --- a/packages/cli-v3/templates/examples/schedule.ts.template +++ b/packages/cli-v3/templates/examples/schedule.ts.template @@ -4,8 +4,8 @@ export const firstScheduledTask = schedules.task({ id: "first-scheduled-task", // Every hour cron: "0 * * * *", - // Set an optional maxDuration to prevent tasks from running indefinitely - maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute + // Set an optional maxComputeSeconds to prevent tasks from running indefinitely + maxComputeSeconds: 300, // Stop executing after 300 secs (5 mins) of compute run: async (payload, { ctx }) => { // The payload contains the last run timestamp that you can use to check if this is the first run // And calculate the time since the last run diff --git a/packages/cli-v3/templates/examples/simple.mjs.template b/packages/cli-v3/templates/examples/simple.mjs.template index 8b1bf12d4f1..054bc2e7cd5 100644 --- a/packages/cli-v3/templates/examples/simple.mjs.template +++ b/packages/cli-v3/templates/examples/simple.mjs.template @@ -2,8 +2,8 @@ import { logger, task, wait } from "@trigger.dev/sdk/v3"; export const helloWorldTask = task({ id: "hello-world", - // Set an optional maxDuration to prevent tasks from running indefinitely - maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute + // Set an optional maxComputeSeconds to prevent tasks from running indefinitely + maxComputeSeconds: 300, // Stop executing after 300 secs (5 mins) of compute run: async (payload, { ctx }) => { logger.log("Hello, world!", { payload, ctx }); diff --git a/packages/cli-v3/templates/examples/simple.ts.template b/packages/cli-v3/templates/examples/simple.ts.template index 9ef3d529f3a..83ae9280412 100644 --- a/packages/cli-v3/templates/examples/simple.ts.template +++ b/packages/cli-v3/templates/examples/simple.ts.template @@ -2,8 +2,8 @@ import { logger, task, wait } from "@trigger.dev/sdk/v3"; export const helloWorldTask = task({ id: "hello-world", - // Set an optional maxDuration to prevent tasks from running indefinitely - maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute + // Set an optional maxComputeSeconds to prevent tasks from running indefinitely + maxComputeSeconds: 300, // Stop executing after 300 secs (5 mins) of compute run: async (payload: any, { ctx }) => { logger.log("Hello, world!", { payload, ctx }); diff --git a/packages/cli-v3/templates/trigger.config.mjs.template b/packages/cli-v3/templates/trigger.config.mjs.template index d50033647e2..5b1e857d341 100644 --- a/packages/cli-v3/templates/trigger.config.mjs.template +++ b/packages/cli-v3/templates/trigger.config.mjs.template @@ -4,10 +4,10 @@ export default defineConfig({ project: "${projectRef}", runtime: "${runtime}", logLevel: "log", - // The max compute seconds a task is allowed to run. If the task run exceeds this duration, it will be stopped. + // The max compute seconds a task is allowed to run. If the run exceeds this, it will be stopped. // You can override this on an individual task. // See https://trigger.dev/docs/runs/max-duration - maxDuration: 3600, + maxComputeSeconds: 3600, retries: { enabledInDev: true, default: { diff --git a/packages/cli-v3/templates/trigger.config.ts.template b/packages/cli-v3/templates/trigger.config.ts.template index d50033647e2..5b1e857d341 100644 --- a/packages/cli-v3/templates/trigger.config.ts.template +++ b/packages/cli-v3/templates/trigger.config.ts.template @@ -4,10 +4,10 @@ export default defineConfig({ project: "${projectRef}", runtime: "${runtime}", logLevel: "log", - // The max compute seconds a task is allowed to run. If the task run exceeds this duration, it will be stopped. + // The max compute seconds a task is allowed to run. If the run exceeds this, it will be stopped. // You can override this on an individual task. // See https://trigger.dev/docs/runs/max-duration - maxDuration: 3600, + maxComputeSeconds: 3600, retries: { enabledInDev: true, default: { From 49a0a0e73180b5947bfbff9749ce06225af3b5fa Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 6 May 2026 16:39:49 +0100 Subject: [PATCH 5/8] chore: changeset for maxComputeSeconds --- .changeset/max-compute-seconds.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/max-compute-seconds.md diff --git a/.changeset/max-compute-seconds.md b/.changeset/max-compute-seconds.md new file mode 100644 index 00000000000..56cac672521 --- /dev/null +++ b/.changeset/max-compute-seconds.md @@ -0,0 +1,7 @@ +--- +"@trigger.dev/core": patch +"@trigger.dev/sdk": patch +"trigger.dev": patch +--- + +Add `maxComputeSeconds` as the user-facing replacement for `maxDuration` on `defineConfig`, task definitions, and trigger options. The new name makes the unit (compute-time seconds) unambiguous at the call site. `maxDuration` is JSDoc-deprecated and still accepted; if both are set, `maxComputeSeconds` wins. The `init` templates have been updated to use the new name. From ce718f3b9284371c2f67f6b7e6055d5c40a11651 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 6 May 2026 21:38:56 +0100 Subject: [PATCH 6/8] chore(references): use maxComputeSeconds in hello-world for manual testing - trigger.config.ts: top-level maxComputeSeconds - example.ts: per-task maxComputeSeconds on maxDurationTask - example.ts: per-trigger override on triggerAndWait Variable name maxDurationTask kept since it labels the legacy fixture concept; the payload.maxDuration field is unrelated to the SDK property and untouched. --- references/hello-world/src/trigger/example.ts | 4 ++-- references/hello-world/trigger.config.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/references/hello-world/src/trigger/example.ts b/references/hello-world/src/trigger/example.ts index a3070d56339..718a2c77ca1 100644 --- a/references/hello-world/src/trigger/example.ts +++ b/references/hello-world/src/trigger/example.ts @@ -139,7 +139,7 @@ export const maxDurationTask = task({ maxTimeoutInMs: 2_000, factor: 1.4, }, - maxDuration: 5, + maxComputeSeconds: 5, run: async (payload: { sleepFor: number }, { signal, ctx }) => { await setTimeout(payload.sleepFor * 1000, { signal }); }, @@ -150,7 +150,7 @@ export const maxDurationParentTask = task({ run: async (payload: { sleepFor?: number; maxDuration?: number }, { ctx, signal }) => { const result = await maxDurationTask.triggerAndWait( { sleepFor: payload.sleepFor ?? 10 }, - { maxDuration: timeout.None } + { maxComputeSeconds: timeout.None } ); return result; diff --git a/references/hello-world/trigger.config.ts b/references/hello-world/trigger.config.ts index e0b875cd6d1..86de9f25a05 100644 --- a/references/hello-world/trigger.config.ts +++ b/references/hello-world/trigger.config.ts @@ -10,7 +10,7 @@ export default defineConfig({ maxExecutionsPerProcess: 20, }, logLevel: "debug", - maxDuration: 3600, + maxComputeSeconds: 3600, ttl: "1h", retries: { enabledInDev: true, From 174c9a38ab984b16c8f4571be4e55dca0efc3666 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Fri, 8 May 2026 09:45:56 +0100 Subject: [PATCH 7/8] Updated the error and link to the docs --- packages/core/src/v3/errors.ts | 10 +++++++++- packages/core/src/v3/links.ts | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/core/src/v3/errors.ts b/packages/core/src/v3/errors.ts index a538ca9357b..079c0402a72 100644 --- a/packages/core/src/v3/errors.ts +++ b/packages/core/src/v3/errors.ts @@ -636,7 +636,9 @@ export class MaxDurationExceededError extends Error { public readonly maxDurationInSeconds: number, public readonly elapsedTimeInSeconds: number ) { - super(`Run exceeded maximum compute time (maxDuration) of ${maxDurationInSeconds} seconds`); + super( + `Run exceeded maximum compute time (maxComputeSeconds) of ${maxDurationInSeconds} seconds` + ); this.name = "MaxDurationExceededError"; } @@ -736,6 +738,12 @@ const prettyInternalErrors: Partial< href: links.docs.troubleshooting.uncaughtException, }, }, + MAX_DURATION_EXCEEDED: { + link: { + name: "How to set maxComputeSeconds (maxDuration)", + href: links.docs.maxDuration, + }, + }, }; const getPrettyTaskRunError = (code: TaskRunInternalError["code"]): TaskRunInternalError => { diff --git a/packages/core/src/v3/links.ts b/packages/core/src/v3/links.ts index 739f9dd28f7..0ce1e08d44a 100644 --- a/packages/core/src/v3/links.ts +++ b/packages/core/src/v3/links.ts @@ -26,6 +26,7 @@ export const links = { personalAccessToken: "https://trigger.dev/docs/github-actions#creating-a-personal-access-token", }, + maxDuration: "https://trigger.dev/docs/runs/max-duration", }, site: { home: "https://trigger.dev", From 5d8e259faf5c64b8fc823e13db05410074051911 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Fri, 8 May 2026 18:42:18 +0100 Subject: [PATCH 8/8] fix(cli): resolve maxComputeSeconds in validateConfig for bypass cases If a user exports a trigger.config plain object without going through defineConfig() (TypeScript allows it), validation previously rejected the new maxComputeSeconds field with an error mentioning maxDuration. Mirror the SDK boundary's resolution at the CLI boundary so downstream internals (which still read maxDuration) keep working. --- packages/cli-v3/src/config.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/cli-v3/src/config.ts b/packages/cli-v3/src/config.ts index af5623e0176..e5e139859ca 100644 --- a/packages/cli-v3/src/config.ts +++ b/packages/cli-v3/src/config.ts @@ -341,11 +341,16 @@ function validateConfig(config: TriggerConfig, warn = true) { config.build.extensions.push(adaptResolveEnvVarsToSyncEnvVarsExtension(resolveEnvVarsFn)); } - if (!config.maxDuration) { + // Resolve maxComputeSeconds → maxDuration so plain-object exports that bypass + // defineConfig() still work. This mirrors the resolution defineConfig() applies + // at the SDK boundary; downstream CLI/runtime code only reads `maxDuration`. + const resolvedMaxDuration = config.maxComputeSeconds ?? config.maxDuration; + if (!resolvedMaxDuration) { throw new Error( - `The "maxDuration" trigger.config option is now required, and must be at least 5 seconds.` + `The "maxComputeSeconds" trigger.config option is now required, and must be at least 5 seconds.` ); } + config.maxDuration = resolvedMaxDuration; if (config.runtime && config.runtime === "bun") { warn &&