Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
9 changes: 9 additions & 0 deletions .changeset/secret-bulk-undeployed-version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"wrangler": patch
---

Show a useful error when `wrangler secret bulk` hits an undeployed latest version

`wrangler secret put` already explained this case (API error 10215). `secret bulk` just dumped the raw API response, which for 10214 talks about logpush and tail_consumers even though you were only uploading secrets.

Both commands now point at `wrangler versions secret …` instead.
79 changes: 78 additions & 1 deletion packages/wrangler/src/__tests__/secret.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import {
import { http, HttpResponse } from "msw";
import * as TOML from "smol-toml";
import { afterEach, beforeEach, describe, it, vi } from "vitest";
import { VERSION_NOT_DEPLOYED_ERR_CODE } from "../secret";
import {
VERSION_NOT_DEPLOYED_ERR_CODE,
VERSION_SETTINGS_NOT_DEPLOYED_ERR_CODE,
} from "../secret";
import {
WORKER_NOT_FOUND_ERR_CODE,
workerNotFoundErrorMessage,
Expand Down Expand Up @@ -1239,6 +1242,80 @@ describe("wrangler secret", () => {
expect(std.warn).toMatchInlineSnapshot(`""`);
});

it("should error if the latest version is not deployed", async ({
expect,
}) => {
writeFileSync(
"secret.json",
JSON.stringify({
"secret-name-1": "secret_text",
})
);

msw.use(
http.patch(
`*/accounts/:accountId/workers/scripts/:scriptName/secrets-bulk`,
async ({ params }) => {
expect(params.accountId).toEqual("some-account-id");
expect(params.scriptName).toEqual("script-name");
return HttpResponse.json(
createFetchResult(null, false, [
{
code: VERSION_NOT_DEPLOYED_ERR_CODE,
message: "latest is not deployed",
},
])
);
},
{ once: true }
)
);

await expect(runWrangler("secret bulk ./secret.json --name script-name"))
.rejects.toThrowErrorMatchingInlineSnapshot(`
[Error: Secret edit failed. You attempted to modify a secret, but the latest version of your Worker isn't currently deployed.
This limitation exists to prevent accidental deployment when using Worker versions and secrets together.
To resolve this, you have two options:
(1) use the \`wrangler versions secret bulk\` instead, which allows you to update secrets without deploying; or
(2) deploy the latest version first, then modify secrets.
Alternatively, you can use the Cloudflare dashboard to modify secrets and deploy the version.]
`);
});

it("should rewrite the logpush/tail_consumers settings error when the latest version is not deployed", async ({
expect,
}) => {
writeFileSync(
"secret.json",
JSON.stringify({
"secret-name-1": "secret_text",
})
);

msw.use(
http.patch(
`*/accounts/:accountId/workers/scripts/:scriptName/secrets-bulk`,
async ({ params }) => {
expect(params.accountId).toEqual("some-account-id");
return HttpResponse.json(
createFetchResult(null, false, [
{
code: VERSION_SETTINGS_NOT_DEPLOYED_ERR_CODE,
message:
"Script edit failed. You attempted to deploy the latest version with modified settings, but the latest version isn't currently deployed.",
},
])
);
},
{ once: true }
)
);

await expect(
runWrangler("secret bulk ./secret.json --name script-name")
).rejects.toThrow(/wrangler versions secret bulk/);
});

it("throws a meaningful error", async ({ expect }) => {
writeFileSync(
"secret.json",
Expand Down
80 changes: 61 additions & 19 deletions packages/wrangler/src/secret/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,46 @@ import { readFromStdin, trimTrailingWhitespace } from "../utils/std";
import type { Config } from "@cloudflare/workers-utils";

export const VERSION_NOT_DEPLOYED_ERR_CODE = 10215;
/** Script-settings edit on an undeployed latest version (logpush / tail_consumers). */
export const VERSION_SETTINGS_NOT_DEPLOYED_ERR_CODE = 10214;

const VERSION_NOT_DEPLOYED_ERR_CODES = [
VERSION_NOT_DEPLOYED_ERR_CODE,
VERSION_SETTINGS_NOT_DEPLOYED_ERR_CODE,
];

/**
* The `wrangler secret` commands edit the currently deployed Worker. If the
* latest version isn't deployed, the API rejects the change with 10214/10215
* and a note about logpush/tail_consumers that doesn't mention secrets.
*
* @param e - Error thrown by the secrets API.
* @param versionsCommand - The `wrangler versions secret …` command that
* updates secrets without deploying.
* @param telemetryMessage - Telemetry identifier for the rewritten error.
* @throws {UserError} When `e` is a version-not-deployed API error.
*/
function throwIfLatestVersionNotDeployed(
e: unknown,
versionsCommand: string,
telemetryMessage: string
): void {
if (
e instanceof APIError &&
e.code !== undefined &&
VERSION_NOT_DEPLOYED_ERR_CODES.includes(e.code)
) {
throw new UserError(
"Secret edit failed. You attempted to modify a secret, but the latest version of your Worker isn't currently deployed.\n" +
"This limitation exists to prevent accidental deployment when using Worker versions and secrets together.\n" +
"To resolve this, you have two options:\n" +
`(1) use the \`${versionsCommand}\` instead, which allows you to update secrets without deploying; or\n` +
"(2) deploy the latest version first, then modify secrets.\n" +
"Alternatively, you can use the Cloudflare dashboard to modify secrets and deploy the version.",
{ telemetryMessage }
);
}
}

type SecretBindingUpload = {
type: "secret_text";
Expand Down Expand Up @@ -154,19 +194,12 @@ export const secretPutCommand = createCommand({
}),
});
} catch (e) {
if (e instanceof APIError && e.code === VERSION_NOT_DEPLOYED_ERR_CODE) {
throw new UserError(
"Secret edit failed. You attempted to modify a secret, but the latest version of your Worker isn't currently deployed.\n" +
"This limitation exists to prevent accidental deployment when using Worker versions and secrets together.\n" +
"To resolve this, you have two options:\n" +
"(1) use the `wrangler versions secret put` instead, which allows you to update secrets without deploying; or\n" +
"(2) deploy the latest version first, then modify secrets.\n" +
"Alternatively, you can use the Cloudflare dashboard to modify secrets and deploy the version.",
{ telemetryMessage: "secret put version not deployed" }
);
} else {
throw e;
}
throwIfLatestVersionNotDeployed(
e,
"wrangler versions secret put",
"secret put version not deployed"
);
throw e;
}
}

Expand Down Expand Up @@ -373,12 +406,21 @@ async function putBulkSecrets(
secrets[key] = null;
}
}
const resp = await fetchResult(config, url, {
method: "PATCH",
headers: { "Content-Type": "application/merge-patch+json" },
body: JSON.stringify({ secrets }),
});
return [resp, toCreate, toDelete];
try {
const resp = await fetchResult(config, url, {
method: "PATCH",
headers: { "Content-Type": "application/merge-patch+json" },
body: JSON.stringify({ secrets }),
});
return [resp, toCreate, toDelete];
} catch (e) {
throwIfLatestVersionNotDeployed(
e,
"wrangler versions secret bulk",
"secret bulk version not deployed"
);
throw e;
}
}

export const secretBulkCommand = createCommand({
Expand Down
Loading