-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
bug: global configure() silently ignores subsequent calls, parallel requests always use first caller's auth #3298
Description
Provide environment information
n/a
Describe the bug
Calling configure() per-request is not safe in parallel contexts (React server actions, Promise.all, etc.). The bug is more severe than a simple overwrite race: configure() calls registerGlobal without allowOverride, so any call after the first is silently dropped. The caller gets no error, no warning, and unknowingly uses the wrong token.
Both runs triggered in parallel end up in the same project (whichever request called configure() first).
Expected: each request uses its own token/project.
Actual: second configure() call returns false silently; both requests use the first token
Reproduction repo
n/a
To reproduce
import "dotenv/config";
import { configure, tasks } from "@trigger.dev/sdk";
const tokenA = process.env.TRIGGER_TOKEN_A;
const tokenB = process.env.TRIGGER_TOKEN_B;
async function simulateRequest(label: string, token: string) {
configure({ accessToken: token });
await new Promise((r) => setImmediate(r)); // simulates any real async yield
const run = await tasks.trigger("fast-task", { i: label });
console.log(`${label} triggered run: ${run.id}`);
return { label, token, runId: run.id };
}
const results = await Promise.all([
simulateRequest("token-A", tokenA),
simulateRequest("token-B", tokenB),
]);
// Both runs appear in token-A's project dashboard, token-B's project gets nothing.
Set TRIGGER_TOKEN_A and TRIGGER_TOKEN_B to tokens from two different projects, then check both dashboards.
Additional information
Workaround:
Use auth.withAuth() per request instead of configure(). Note: withAuth uses runWithConfig which passes allowOverride = true, so it does write the config, but save/restore around an async function is still not safe across concurrent calls.
Fix direction:
AsyncLocalStorage (or equivalent) for per-async-context config isolation.