Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-envvars-update-name.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
---
"@trigger.dev/sdk": patch
---

Fix `envvars.update()` throwing `ReferenceError: name is not defined` when called outside a task context. The non-task branch referenced an out-of-scope `name` variable instead of the `nameOrRequestOptions` parameter (#4264).
67 changes: 67 additions & 0 deletions packages/trigger-sdk/src/v3/envvars.test.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
import { createServer, type Server, type ServerResponse } from "node:http";
import type { AddressInfo } from "node:net";
import { apiClientManager } from "@trigger.dev/core/v3";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import * as envvars from "./envvars.js";

type ReceivedRequest = {
method: string;
url: string;
};

describe("envvars.update outside a task context (GH #4264)", () => {
let server: Server;
let baseUrl: string;
let requests: ReceivedRequest[];

beforeEach(async () => {
requests = [];
server = createServer((request, response) => {
requests.push({ method: request.method ?? "", url: request.url ?? "" });
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify({ success: true }));
});
await new Promise<void>((resolve) => {
server.listen(0, "127.0.0.1", () => {
baseUrl = `http://127.0.0.1:${(server.address() as AddressInfo).port}`;
resolve();
});
});
});

afterEach(async () => {
await new Promise<void>((resolve) => server.close(() => resolve()));
});

it("resolves the name argument instead of throwing ReferenceError", async () => {
const key = "tr_prod_0123456789abcdefghijklmn";

// Outside a task context, taskContext.ctx is undefined. Before the fix this
// path evaluated `$name = name!`, but the implementation signature has no
// `name` parameter, so it threw `ReferenceError: name is not defined`.
await apiClientManager.runWithConfig({ baseURL: baseUrl, accessToken: key }, async () => {
try {
await envvars.update("proj_ref", "prod", "MY_SECRET", { value: "abc" });
} catch (err) {
// Response-shape concerns are irrelevant here; only assert the
// argument-resolution crash is gone.
expect((err as Error).message).not.toContain("name is not defined");
}
});

const updateRequest = requests.find((request) => request.url.includes("MY_SECRET"));
expect(updateRequest).toBeDefined();
expect(updateRequest!.url).toContain("/projects/proj_ref/envvars/prod/MY_SECRET");
});

it("throws a clear error when the name is missing", async () => {
const key = "tr_prod_0123456789abcdefghijklmn";

await apiClientManager.runWithConfig({ baseURL: baseUrl, accessToken: key }, async () => {
await expect(
// @ts-expect-error deliberately omitting the name argument
envvars.update("proj_ref", "prod", { value: "abc" })
).rejects.toThrow("name is required");
});
});
Comment on lines +57 to +66

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Second test will fail: update() throws synchronously and hits the params check first

envvars.update("proj_ref", "prod", { value: "abc" }) maps to projectRefOrName="proj_ref", slugOrParams="prod", nameOrRequestOptions={value:"abc"}, params=undefined. In packages/trigger-sdk/src/v3/envvars.ts:335-337 the if (!params) throw new Error("params is required") check runs before the newly added name check, so the message is "params is required", not "name is required". Moreover the throw is synchronous (the function never returns a promise in this path), so await expect(envvars.update(...)).rejects.toThrow(...) will not catch it — the argument expression throws while being evaluated and the test errors out. This test needs expect(() => envvars.update(...)).toThrow(...) and a case that actually reaches the name check (e.g. update("proj_ref", "prod", undefined as any, { value: "abc" })).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

});
6 changes: 5 additions & 1 deletion packages/trigger-sdk/src/v3/envvars.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -336,9 +336,13 @@ export function update(
throw new Error("params is required");
}

if (typeof nameOrRequestOptions !== "string") {
throw new Error("name is required");
}

$projectRef = projectRefOrName;
$slug = slugOrParams;
$name = name!;
$name = nameOrRequestOptions;
$params = params;
Comment on lines +339 to 346

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Pre-existing mis-assignment in the in-task branch of update()

In the taskContext.ctx branch, $projectRef = slugOrParams and $slug = slugOrParams ?? ctx.environment.slug both take the same argument (packages/trigger-sdk/src/v3/envvars.ts:307-313), and $name falls back to ctx.environment.slug when no name is given. For the 4-arg overload called inside a task this sends the slug as the project ref, so envvars.update(projectRef, slug, name, params) inside a task targets the wrong project. This is outside the diff hunks but is the same argument-routing family of bugs the PR is fixing and would be worth correcting in the same pass (correct form mirrors create/upload: $projectRef = projectRefOrName, $slug = typeof slugOrParams === "string" ? slugOrParams : ctx.environment.slug).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

}

Expand Down