From 305a7ffc31d68f63528e539a6f7c650d1dda7e02 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Tue, 23 Sep 2025 14:58:59 +0100 Subject: [PATCH 1/6] Improve error logging --- .../src/__tests__/cfetch-utils.test.ts | 15 ++- .../wrangler/src/__tests__/deploy.test.ts | 104 +++++++++++++----- .../__tests__/pages/functions-build.test.ts | 10 +- .../__tests__/pages/pages-build-env.test.ts | 10 +- .../pages/pages-download-config.test.ts | 25 +++-- .../src/__tests__/pages/secret.test.ts | 19 ++-- packages/wrangler/src/__tests__/r2.test.ts | 29 +++-- .../wrangler/src/__tests__/secret.test.ts | 26 +++-- .../wrangler/src/api/startDevWorker/DevEnv.ts | 4 +- packages/wrangler/src/dev/remote.ts | 84 +++++++------- packages/wrangler/src/index.ts | 4 +- packages/wrangler/src/logger.ts | 21 +++- packages/wrangler/src/utils/isAbortError.ts | 2 +- 13 files changed, 230 insertions(+), 123 deletions(-) diff --git a/packages/wrangler/src/__tests__/cfetch-utils.test.ts b/packages/wrangler/src/__tests__/cfetch-utils.test.ts index e2f1054f2e5..d6dddf57147 100644 --- a/packages/wrangler/src/__tests__/cfetch-utils.test.ts +++ b/packages/wrangler/src/__tests__/cfetch-utils.test.ts @@ -147,10 +147,10 @@ describe("throwFetchError", () => { `[APIError: A request to the Cloudflare API (/user) failed.]` ); - expect(std.out).toMatchInlineSnapshot(` - "Getting User settings... - - X [ERROR] A request to the Cloudflare API (/user) failed. + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "X [ERROR] A request to the Cloudflare API (/user) failed. error one [code: 10001] To learn more about this error, visit: https://example.com/1 @@ -169,7 +169,12 @@ describe("throwFetchError", () => { If you think this is a bug, please open an issue at: https://github.com/cloudflare/workers-sdk/issues/new/choose - " + ", + "info": "", + "out": "Getting User settings... + ", + "warn": "", + } `); }); diff --git a/packages/wrangler/src/__tests__/deploy.test.ts b/packages/wrangler/src/__tests__/deploy.test.ts index 2d733c0de86..a6ea03716e1 100644 --- a/packages/wrangler/src/__tests__/deploy.test.ts +++ b/packages/wrangler/src/__tests__/deploy.test.ts @@ -456,29 +456,29 @@ describe("deploy", () => { `[APIError: A request to the Cloudflare API (/accounts/some-account-id/workers/services/test-name) failed.]` ); expect(std.out).toMatchInlineSnapshot(` - " - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/services/test-name) failed. + " + X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/services/test-name) failed. Authentication error [code: 10000] - 📎 It looks like you are authenticating Wrangler via a custom API token set in an environment variable. - Please ensure it has the correct permissions for this operation. - - Getting User settings... - ℹ️ The API Token is read from the CLOUDFLARE_API_TOKEN environment variable. - 👋 You are logged in with an User API Token, associated with the email user@example.com. - ┌───────────────┬────────────┐ - │ Account Name │ Account ID │ - ├───────────────┼────────────┤ - │ Account One │ account-1 │ - ├───────────────┼────────────┤ - │ Account Two │ account-2 │ - ├───────────────┼────────────┤ - │ Account Three │ account-3 │ - └───────────────┴────────────┘ - 🔓 To see token permissions visit https://dash.cloudflare.com/profile/api-tokens." - `); + 📎 It looks like you are authenticating Wrangler via a custom API token set in an environment variable. + Please ensure it has the correct permissions for this operation. + + Getting User settings... + 👋 You are logged in with an User API Token, associated with the email user@example.com. + ℹ️ The API Token is read from the CLOUDFLARE_API_TOKEN environment variable. + ┌─┬─┐ + │ Account Name │ Account ID │ + ├─┼─┤ + │ Account One │ account-1 │ + ├─┼─┤ + │ Account Two │ account-2 │ + ├─┼─┤ + │ Account Three │ account-3 │ + └─┴─┘ + 🔓 To see token permissions visit https://dash.cloudflare.com/profile/api-tokens." + `); }); it("should error helpfully if pages_build_output_dir is set in wrangler.toml", async () => { @@ -11563,7 +11563,6 @@ export default{ "err": "", "info": "", "out": "Total Upload: xx KiB / gzip: xx KiB - No bindings found. X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) failed. @@ -11573,6 +11572,9 @@ export default{ If you think this is a bug, please open an issue at: https://github.com/cloudflare/workers-sdk/issues/new/choose + ", + "info": "", + "out": "Total Upload: xx KiB / gzip: xx KiB ", "warn": "", } @@ -11633,10 +11635,25 @@ export default{ expect(std).toMatchInlineSnapshot(` Object { "debug": "", - "err": "", + "err": "X [ERROR] Your Worker failed validation because it exceeded size limits. + + + A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) + failed. + - workers.api.error.script_too_large [code: 10027] + Here are the 4 largest dependencies included in your script: + + - index.js - xx KiB + - add.wasm - xx KiB + - dependency.js - xx KiB + - message.txt - xx KiB + + If these are unnecessary, consider removing them + + + ", "info": "", "out": "Total Upload: xx KiB / gzip: xx KiB - No bindings found. X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) failed. @@ -11645,6 +11662,9 @@ export default{ If you think this is a bug, please open an issue at: https://github.com/cloudflare/workers-sdk/issues/new/choose + ", + "info": "", + "out": "Total Upload: xx KiB / gzip: xx KiB ", "warn": "▲ [WARNING] Here are the 4 largest dependencies included in your script: @@ -11695,9 +11715,43 @@ export default{ main: "index.js", }); - await expect(runWrangler("deploy")).rejects.toThrowError( - `Your Worker failed validation because it exceeded startup limits.` - ); + await expect(runWrangler("deploy")).rejects.toThrowError(); + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "X [ERROR] Your Worker failed validation because it exceeded startup limits. + + + A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) + failed. + - Error: Script startup exceeded CPU time limit. [code: 10021] + + To ensure fast responses, there are constraints on Worker startup, such as how much CPU it can + use, or how long it can take. Your Worker has hit one of these startup limits. Try reducing the + amount of work done during startup (outside the event handler), either by removing code or + relocating it inside the event handler. + + Refer to https://developers.cloudflare.com/workers/platform/limits/#worker-startup-time for more + details + A CPU Profile of your Worker's startup phase has been written to + .wrangler/tmp/startup-profile-/worker.cpuprofile - load it into the Chrome DevTools profiler + (or directly in VSCode) to view a flamegraph. + + ", + "info": "", + "out": "Total Upload: xx KiB / gzip: xx KiB + + X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) failed. + + Error: Script startup exceeded CPU time limit. [code: 10021] + + If you think this is a bug, please open an issue at: + https://github.com/cloudflare/workers-sdk/issues/new/choose + + ", + "warn": "", + } + `); }); describe("unit tests", () => { diff --git a/packages/wrangler/src/__tests__/pages/functions-build.test.ts b/packages/wrangler/src/__tests__/pages/functions-build.test.ts index daa2f35b8ad..6579c504b89 100644 --- a/packages/wrangler/src/__tests__/pages/functions-build.test.ts +++ b/packages/wrangler/src/__tests__/pages/functions-build.test.ts @@ -1142,6 +1142,14 @@ export default { expect(buildMetadataExists).toBeFalsy(); // This logs a parsing error, but continues anyway - expect(std.err).toContain("ParseError"); + expect(std.err).toMatchInlineSnapshot(` + "X [ERROR] Unexpected character, expected only whitespace or comments till end of line + + /wrangler.toml:5:23: +  5 │ limits = { cpu_ms = 50 }\\" + ╵ ^ + + " + `); }); }); diff --git a/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts b/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts index 05ae2fe7244..6de750e90d6 100644 --- a/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts +++ b/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts @@ -120,7 +120,15 @@ describe("pages build env", () => { await runWrangler("pages functions build-env . --outfile data.json"); expect(process.exitCode).toEqual(EXIT_CODE_INVALID_PAGES_CONFIG); - expect(std.err).toContain("ParseError"); + expect(std.err).toMatchInlineSnapshot(` + "X [ERROR] Invalid character, expected \\"=\\" + + /wrangler.toml:1:8: +  1 │ INVALID \\"FILE + ╵ ^ + + " + `); expect(std.out).toMatchInlineSnapshot(` "Checking for configuration in a Wrangler configuration file (BETA) diff --git a/packages/wrangler/src/__tests__/pages/pages-download-config.test.ts b/packages/wrangler/src/__tests__/pages/pages-download-config.test.ts index 57b14ed6ac1..706bbe6e70f 100644 --- a/packages/wrangler/src/__tests__/pages/pages-download-config.test.ts +++ b/packages/wrangler/src/__tests__/pages/pages-download-config.test.ts @@ -863,18 +863,25 @@ describe("pages download config", () => { ).rejects.toThrowErrorMatchingInlineSnapshot( `[APIError: A request to the Cloudflare API (/accounts/MOCK_ACCOUNT_ID/pages/projects/NOT_REAL) failed.]` ); - expect(std.out).toMatchInlineSnapshot(` - " - X [ERROR] A request to the Cloudflare API (/accounts/MOCK_ACCOUNT_ID/pages/projects/NOT_REAL) failed. + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "X [ERROR] A request to the Cloudflare API (/accounts/MOCK_ACCOUNT_ID/pages/projects/NOT_REAL) failed. - Project not found. The specified project name does not match any of your existing projects. [code: - 8000007] + Project not found. The specified project name does not match any of your existing projects. [code: + 8000007] - If you think this is a bug, please open an issue at: - https://github.com/cloudflare/workers-sdk/issues/new/choose + If you think this is a bug, please open an issue at: + https://github.com/cloudflare/workers-sdk/issues/new/choose - " - `); + ", + "info": "", + "out": "", + "warn": "▲ [WARNING] 🚧 \`wrangler pages download config\` is an experimental command. Please report any issues to https://github.com/cloudflare/workers-sdk/issues/new/choose + + ", + } + `); }); describe("overwrite existing file", () => { it("should overwrite existing file w/ --force", async () => { diff --git a/packages/wrangler/src/__tests__/pages/secret.test.ts b/packages/wrangler/src/__tests__/pages/secret.test.ts index 7a2e871cfaf..737df81fd1a 100644 --- a/packages/wrangler/src/__tests__/pages/secret.test.ts +++ b/packages/wrangler/src/__tests__/pages/secret.test.ts @@ -737,19 +737,24 @@ describe("wrangler pages secret", () => { `[APIError: A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/script-name/settings) failed.]` ); - expect(std.out).toMatchInlineSnapshot(` - "🌀 Creating the secrets for the Worker \\"script-name\\" - - 🚨 Secrets failed to upload - - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/script-name/settings) failed. + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/script-name/settings) failed. This is a helpful error [code: 1] If you think this is a bug, please open an issue at: https://github.com/cloudflare/workers-sdk/issues/new/choose - " + ", + "info": "", + "out": "🌀 Creating the secrets for the Worker \\"script-name\\" + + 🚨 Secrets failed to upload + ", + "warn": "", + } `); }); }); diff --git a/packages/wrangler/src/__tests__/r2.test.ts b/packages/wrangler/src/__tests__/r2.test.ts index 39c4bd7eb46..b1a2fb3bfe6 100644 --- a/packages/wrangler/src/__tests__/r2.test.ts +++ b/packages/wrangler/src/__tests__/r2.test.ts @@ -438,17 +438,22 @@ describe("r2", () => { ).rejects.toThrowErrorMatchingInlineSnapshot( `[APIError: A request to the Cloudflare API (/accounts/some-account-id/r2/buckets) failed.]` ); - expect(std.out).toMatchInlineSnapshot(` - "Creating bucket 'test-bucket'... - - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/r2/buckets) failed. + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/r2/buckets) failed. The JSON you provided was not well formed. [code: 10040] If you think this is a bug, please open an issue at: https://github.com/cloudflare/workers-sdk/issues/new/choose - " + ", + "info": "", + "out": "Creating bucket 'test-bucket'... + ", + "warn": "", + } `); }); }); @@ -524,17 +529,9 @@ describe("r2", () => { `[APIError: A request to the Cloudflare API (/accounts/some-account-id/r2/buckets/testBucket) failed.]` ); expect(std.out).toMatchInlineSnapshot(` - "Updating bucket testBucket to Foo default storage class. - - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/r2/buckets/testBucket) failed. - - The storage class specified is not valid. [code: 10062] - - If you think this is a bug, please open an issue at: - https://github.com/cloudflare/workers-sdk/issues/new/choose - - " - `); + "Updating bucket testBucket to Foo default storage class. + " + `); }); it("should update the default storage class", async () => { diff --git a/packages/wrangler/src/__tests__/secret.test.ts b/packages/wrangler/src/__tests__/secret.test.ts index c4c73468a37..c7766f045a1 100644 --- a/packages/wrangler/src/__tests__/secret.test.ts +++ b/packages/wrangler/src/__tests__/secret.test.ts @@ -1092,23 +1092,27 @@ describe("wrangler secret", () => { `[APIError: A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/script-name/settings) failed.]` ); - expect(std.out).toMatchInlineSnapshot(` - " - ⛅️ wrangler x.x.x - ------------------ - - 🌀 Creating the secrets for the Worker \\"script-name\\" - - 🚨 Secrets failed to upload - - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/script-name/settings) failed. + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/script-name/settings) failed. This is a helpful error [code: 1] If you think this is a bug, please open an issue at: https://github.com/cloudflare/workers-sdk/issues/new/choose - " + ", + "info": "", + "out": " + ⛅️ wrangler x.x.x + ────────────────── + 🌀 Creating the secrets for the Worker \\"script-name\\" + + 🚨 Secrets failed to upload + ", + "warn": "", + } `); }); diff --git a/packages/wrangler/src/api/startDevWorker/DevEnv.ts b/packages/wrangler/src/api/startDevWorker/DevEnv.ts index 811f3d4f12d..7ad5cc16b67 100644 --- a/packages/wrangler/src/api/startDevWorker/DevEnv.ts +++ b/packages/wrangler/src/api/startDevWorker/DevEnv.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import { EventEmitter } from "node:events"; import { logger } from "../../logger"; -import { formatMessage, ParseError } from "../../parse"; +import { ParseError } from "../../parse"; import { BundlerController } from "./BundlerController"; import { ConfigController } from "./ConfigController"; import { LocalRuntimeController } from "./LocalRuntimeController"; @@ -123,7 +123,7 @@ export class DevEnv extends EventEmitter { ev.source === "ConfigController" && ev.cause instanceof ParseError ) { - logger.log(formatMessage(ev.cause)); + logger.error(ev.cause); } // if other knowable + recoverable errors occur, handle them here else { diff --git a/packages/wrangler/src/dev/remote.ts b/packages/wrangler/src/dev/remote.ts index ca17f2833af..fc946539589 100644 --- a/packages/wrangler/src/dev/remote.ts +++ b/packages/wrangler/src/dev/remote.ts @@ -7,7 +7,7 @@ import { withSourceURLs } from "../deployment-bundle/source-url"; import { getInferredHost } from "../dev"; import { UserError } from "../errors"; import { logger } from "../logger"; -import { syncLegacyAssets } from "../sites"; +import { syncWorkersSite } from "../sites"; import { requireApiToken } from "../user"; import { isAbortError } from "../utils/isAbortError"; import { getZoneIdForPreview } from "../zones"; @@ -19,6 +19,7 @@ import type { CfWorkerContext, CfWorkerInit, } from "../deployment-bundle/worker"; +import type { ComplianceConfig } from "../environment-variables/misc-variables"; import type { ParseError } from "../parse"; import type { LegacyAssetPaths } from "../sites"; import type { CfAccount } from "./create-worker-preview"; @@ -33,7 +34,7 @@ export function handlePreviewSessionUploadError( // since it could recover after the developer fixes whatever's wrong // instead of logging the raw API error to the user, // give them friendly instructions - if (isAbortError(err)) { + if (!isAbortError(err)) { // code 10049 happens when the preview token expires if ("code" in err && err.code === 10049) { logger.log("Preview token expired, fetching a new one"); @@ -42,7 +43,7 @@ export function handlePreviewSessionUploadError( // lets increment the counter, and trigger a rerun of // the useEffect above return true; - } else if (!handleUserFriendlyError(err as ParseError, accountId)) { + } else if (!handleUserFriendlyError(err, accountId)) { logger.error("Error on remote worker:", err); } } @@ -76,7 +77,7 @@ export function handlePreviewSessionCreationError( } // we want to log the error, but not end the process // since it could recover after the developer fixes whatever's wrong - else if (isAbortError(err)) { + else if (!isAbortError(err)) { logger.error("Error while creating remote dev session:", err); } } @@ -228,49 +229,52 @@ export async function getWorkerAccountAndContext(props: { * messages, does not perform any logic other than logging errors. * @returns if the error was handled or not */ -function handleUserFriendlyError(error: ParseError, accountId?: string) { - switch ((error as unknown as { code: number }).code) { - // code 10021 is a validation error - case 10021: { - // if it is the following message, give a more user friendly - // error, otherwise do not handle this error in this function - if ( - error.notes[0].text === - "binding DB of type d1 must have a valid `id` specified [code: 10021]" - ) { - const errorMessage = - "Error: You must use a real database in the preview_database_id configuration."; - const solutionMessage = - "You can find your databases using 'wrangler d1 list', or read how to develop locally with D1 here:"; - const documentationLink = `https://developers.cloudflare.com/d1/configuration/local-development`; +function handleUserFriendlyError(error: unknown, accountId?: string) { + if (error instanceof APIError) { + switch (error.code) { + // code 10021 is a validation error + case 10021: { + // if it is the following message, give a more user friendly + // error, otherwise do not handle this error in this function + if ( + error.notes[0].text === + "binding DB of type d1 must have a valid `id` specified [code: 10021]" + ) { + const errorMessage = + "Error: You must use a real database in the preview_database_id configuration."; + const solutionMessage = + "You can find your databases using 'wrangler d1 list', or read how to develop locally with D1 here:"; + const documentationLink = `https://developers.cloudflare.com/d1/configuration/local-development`; - logger.error( - `${errorMessage}\n${solutionMessage}\n${documentationLink}` - ); + logger.error( + `${errorMessage}\n${solutionMessage}\n${documentationLink}` + ); - return true; - } + return true; + } - return false; - } + return false; + } - // for error 10063 (workers.dev subdomain required) - case 10063: { - const errorMessage = - "Error: You need to register a workers.dev subdomain before running the dev command in remote mode"; - const solutionMessage = - "You can either enable local mode by pressing l, or register a workers.dev subdomain here:"; - const onboardingLink = accountId - ? `https://dash.cloudflare.com/${accountId}/workers/onboarding` - : "https://dash.cloudflare.com/?to=/:account/workers/onboarding"; + // for error 10063 (workers.dev subdomain required) + case 10063: { + const errorMessage = + "Error: You need to register a workers.dev subdomain before running the dev command in remote mode"; + const solutionMessage = + "You can either enable local mode by pressing l, or register a workers.dev subdomain here:"; + const onboardingLink = accountId + ? `https://dash.cloudflare.com/${accountId}/workers/onboarding` + : "https://dash.cloudflare.com/?to=/:account/workers/onboarding"; - logger.error(`${errorMessage}\n${solutionMessage}\n${onboardingLink}`); + logger.error(`${errorMessage}\n${solutionMessage}\n${onboardingLink}`); - return true; - } + return true; + } - default: { - return false; + default: { + logger.error(error); + return true; + } } } } diff --git a/packages/wrangler/src/index.ts b/packages/wrangler/src/index.ts index 226d776c72f..877a7bb12e2 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -1101,7 +1101,7 @@ export async function main(argv: string[]): Promise { } else if (isAuthenticationError(e)) { mayReport = false; errorType = "AuthenticationError"; - logger.log(formatMessage(e)); + logger.error(e); const envAuth = getAuthFromEnv(); if (envAuth !== undefined && "apiToken" in envAuth) { const message = @@ -1115,7 +1115,7 @@ export async function main(argv: string[]): Promise { e.notes.push({ text: "\nIf you think this is a bug, please open an issue at: https://github.com/cloudflare/workers-sdk/issues/new/choose", }); - logger.log(formatMessage(e)); + logger.error(e); } else if (e instanceof JsonFriendlyFatalError) { logger.log(e.message); } else if ( diff --git a/packages/wrangler/src/logger.ts b/packages/wrangler/src/logger.ts index e33206f012b..7ad07837819 100644 --- a/packages/wrangler/src/logger.ts +++ b/packages/wrangler/src/logger.ts @@ -4,6 +4,7 @@ import CLITable from "cli-table3"; import { formatMessagesSync } from "esbuild"; import { getEnvironmentVariableFactory } from "./environment-variables/factory"; import { getSanitizeLogs } from "./environment-variables/misc-variables"; +import { formatMessage, ParseError } from "./parse"; import { appendToDebugLogFile } from "./utils/log-file"; import type { Message } from "esbuild"; @@ -85,7 +86,16 @@ export class Logger { info = (...args: unknown[]) => this.doLog("info", args); log = (...args: unknown[]) => this.doLog("log", args); warn = (...args: unknown[]) => this.doLog("warn", args); - error = (...args: unknown[]) => this.doLog("error", args); + + error(...args: unknown[]): void; + error(error: ParseError): void; + error(...args: unknown[] | [ParseError]) { + if (args.length === 1 && args[0] instanceof ParseError) { + this.doLog("error", formatMessage(args[0])); + } else { + this.doLog("error", args); + } + } table(data: TableRow[]) { const keys: Keys[] = data.length === 0 ? [] : (Object.keys(data[0]) as Keys[]); @@ -134,8 +144,13 @@ export class Logger { } } - private doLog(messageLevel: Exclude, args: unknown[]) { - const message = this.formatMessage(messageLevel, format(...args)); + private doLog( + messageLevel: Exclude, + args: unknown[] | string + ) { + const message = Array.isArray(args) + ? this.formatMessage(messageLevel, format(...args)) + : args; // unless in unit-tests, send ALL logs to the debug log file (even non-debug logs for context & order) const inUnitTests = typeof vitest !== "undefined"; diff --git a/packages/wrangler/src/utils/isAbortError.ts b/packages/wrangler/src/utils/isAbortError.ts index 0428d70665c..a684e5fcba2 100644 --- a/packages/wrangler/src/utils/isAbortError.ts +++ b/packages/wrangler/src/utils/isAbortError.ts @@ -7,7 +7,7 @@ * https://developer.mozilla.org/en-US/docs/Web/API/DOMException#aborterror */ export function isAbortError(err: unknown) { - const legacyAbortErroCheck = (err as { code: string }).code !== "ABORT_ERR"; + const legacyAbortErroCheck = (err as { code: string }).code == "ABORT_ERR"; const abortErrorCheck = err instanceof Error && err.name == "AbortError"; return legacyAbortErroCheck || abortErrorCheck; From 4d7ef6e52407e555dce5cd103da43fa7db918423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Somhairle=20MacLe=C3=B2id?= Date: Wed, 24 Sep 2025 17:08:37 +0100 Subject: [PATCH 2/6] Create spotty-knives-roll.md --- .changeset/spotty-knives-roll.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/spotty-knives-roll.md diff --git a/.changeset/spotty-knives-roll.md b/.changeset/spotty-knives-roll.md new file mode 100644 index 00000000000..082c430891c --- /dev/null +++ b/.changeset/spotty-knives-roll.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +Improve formatting of logged errors in some cases From bb3ff1d7304dd53d8ebd68a365bd4b85d5c3712a Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Fri, 26 Sep 2025 13:32:05 +0100 Subject: [PATCH 3/6] fix lint --- packages/wrangler/src/dev/remote.ts | 5 ++--- packages/wrangler/src/index.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/wrangler/src/dev/remote.ts b/packages/wrangler/src/dev/remote.ts index fc946539589..21afbe6186c 100644 --- a/packages/wrangler/src/dev/remote.ts +++ b/packages/wrangler/src/dev/remote.ts @@ -7,7 +7,8 @@ import { withSourceURLs } from "../deployment-bundle/source-url"; import { getInferredHost } from "../dev"; import { UserError } from "../errors"; import { logger } from "../logger"; -import { syncWorkersSite } from "../sites"; +import { APIError } from "../parse"; +import { syncLegacyAssets } from "../sites"; import { requireApiToken } from "../user"; import { isAbortError } from "../utils/isAbortError"; import { getZoneIdForPreview } from "../zones"; @@ -19,8 +20,6 @@ import type { CfWorkerContext, CfWorkerInit, } from "../deployment-bundle/worker"; -import type { ComplianceConfig } from "../environment-variables/misc-variables"; -import type { ParseError } from "../parse"; import type { LegacyAssetPaths } from "../sites"; import type { CfAccount } from "./create-worker-preview"; import type { EsbuildBundle } from "./use-esbuild"; diff --git a/packages/wrangler/src/index.ts b/packages/wrangler/src/index.ts index 877a7bb12e2..e5a065f52c1 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -80,7 +80,7 @@ import { import { mTlsCertificateCommands } from "./mtls-certificate/cli"; import { writeOutput } from "./output"; import { pages } from "./pages"; -import { APIError, formatMessage, ParseError } from "./parse"; +import { APIError, ParseError } from "./parse"; import { pipelines } from "./pipelines"; import { pubSubCommands } from "./pubsub/pubsub-commands"; import { queues } from "./queues/cli/commands"; From 05d895d91b2f85c99d6e0408cffc461655b59d14 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Fri, 26 Sep 2025 14:24:28 +0100 Subject: [PATCH 4/6] fix tests --- .../wrangler/src/__tests__/deploy.test.ts | 39 +++++++------------ .../pages/pages-download-config.test.ts | 4 +- .../wrangler/src/__tests__/pipelines.test.ts | 38 +++++++++++------- .../wrangler/src/__tests__/queues.test.ts | 16 ++------ .../wrangler/src/__tests__/secret.test.ts | 3 +- .../wrangler/src/__tests__/sentry.test.ts | 20 +++++----- 6 files changed, 54 insertions(+), 66 deletions(-) diff --git a/packages/wrangler/src/__tests__/deploy.test.ts b/packages/wrangler/src/__tests__/deploy.test.ts index a7ee969e148..0175a7818fc 100644 --- a/packages/wrangler/src/__tests__/deploy.test.ts +++ b/packages/wrangler/src/__tests__/deploy.test.ts @@ -452,26 +452,21 @@ describe("deploy", () => { ); expect(std.out).toMatchInlineSnapshot(` " - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/services/test-name) failed. - - Authentication error [code: 10000] - - 📎 It looks like you are authenticating Wrangler via a custom API token set in an environment variable. Please ensure it has the correct permissions for this operation. Getting User settings... - 👋 You are logged in with an User API Token, associated with the email user@example.com. ℹ️ The API Token is read from the CLOUDFLARE_API_TOKEN environment variable. - ┌─┬─┐ - │ Account Name │ Account ID │ - ├─┼─┤ - │ Account One │ account-1 │ - ├─┼─┤ - │ Account Two │ account-2 │ - ├─┼─┤ - │ Account Three │ account-3 │ - └─┴─┘ + 👋 You are logged in with an User API Token, associated with the email user@example.com. + ┌───────────────┬────────────┐ + │ Account Name │ Account ID │ + ├───────────────┼────────────┤ + │ Account One │ account-1 │ + ├───────────────┼────────────┤ + │ Account Two │ account-2 │ + ├───────────────┼────────────┤ + │ Account Three │ account-3 │ + └───────────────┴────────────┘ 🔓 To see token permissions visit https://dash.cloudflare.com/profile/api-tokens." `); }); @@ -11555,11 +11550,7 @@ export default{ expect(std).toMatchInlineSnapshot(` Object { "debug": "", - "err": "", - "info": "", - "out": "Total Upload: xx KiB / gzip: xx KiB - - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) failed. + "err": "X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) failed. Worker Startup Timed out. This could be due to script exceeding size limits or expensive code in the global scope. [code: 11337] @@ -11570,6 +11561,7 @@ export default{ ", "info": "", "out": "Total Upload: xx KiB / gzip: xx KiB + No bindings found. ", "warn": "", } @@ -11646,9 +11638,6 @@ export default{ If these are unnecessary, consider removing them - ", - "info": "", - "out": "Total Upload: xx KiB / gzip: xx KiB X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) failed. @@ -11660,9 +11649,7 @@ export default{ ", "info": "", "out": "Total Upload: xx KiB / gzip: xx KiB - ", - "info": "", - "out": "Total Upload: xx KiB / gzip: xx KiB + No bindings found. ", "warn": "", } diff --git a/packages/wrangler/src/__tests__/pages/pages-download-config.test.ts b/packages/wrangler/src/__tests__/pages/pages-download-config.test.ts index 706bbe6e70f..5851a12c47b 100644 --- a/packages/wrangler/src/__tests__/pages/pages-download-config.test.ts +++ b/packages/wrangler/src/__tests__/pages/pages-download-config.test.ts @@ -877,9 +877,7 @@ describe("pages download config", () => { ", "info": "", "out": "", - "warn": "▲ [WARNING] 🚧 \`wrangler pages download config\` is an experimental command. Please report any issues to https://github.com/cloudflare/workers-sdk/issues/new/choose - - ", + "warn": "", } `); }); diff --git a/packages/wrangler/src/__tests__/pipelines.test.ts b/packages/wrangler/src/__tests__/pipelines.test.ts index 2dd1d2cc730..7e806e3a84c 100644 --- a/packages/wrangler/src/__tests__/pipelines.test.ts +++ b/packages/wrangler/src/__tests__/pipelines.test.ts @@ -462,14 +462,17 @@ describe("pipelines", () => { await endEventLoop(); - expect(std.err).toMatchInlineSnapshot(`""`); - expect(normalizeOutput(std.out)).toMatchInlineSnapshot(` - "Retrieving config for Pipeline \\"bad-pipeline\\". - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/pipelines/bad-pipeline) failed. + expect(std.err).toMatchInlineSnapshot(` + "X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/pipelines/bad-pipeline) failed. + Pipeline does not exist [code: 1000] + If you think this is a bug, please open an issue at: - https://github.com/cloudflare/workers-sdk/issues/new/choose" + https://github.com/cloudflare/workers-sdk/issues/new/choose + + " `); + expect(normalizeOutput(std.out)).toMatchInlineSnapshot(`"Retrieving config for Pipeline \\"bad-pipeline\\"."`); expect(requests.count).toEqual(1); }); }); @@ -592,13 +595,17 @@ describe("pipelines", () => { await endEventLoop(); - expect(std.err).toMatchInlineSnapshot(`""`); - expect(normalizeOutput(std.out)).toMatchInlineSnapshot(` - "X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/pipelines/bad-pipeline) failed. + expect(std.err).toMatchInlineSnapshot(` + "X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/pipelines/bad-pipeline) failed. + Pipeline does not exist [code: 1000] + If you think this is a bug, please open an issue at: - https://github.com/cloudflare/workers-sdk/issues/new/choose" + https://github.com/cloudflare/workers-sdk/issues/new/choose + + " `); + expect(normalizeOutput(std.out)).toMatchInlineSnapshot(`""`); expect(requests.count).toEqual(1); }); }); @@ -627,14 +634,17 @@ describe("pipelines", () => { await endEventLoop(); - expect(std.err).toMatchInlineSnapshot(`""`); - expect(normalizeOutput(std.out)).toMatchInlineSnapshot(` - "Deleting Pipeline bad-pipeline. - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/pipelines/bad-pipeline) failed. + expect(std.err).toMatchInlineSnapshot(` + "X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/pipelines/bad-pipeline) failed. + Pipeline does not exist [code: 1000] + If you think this is a bug, please open an issue at: - https://github.com/cloudflare/workers-sdk/issues/new/choose" + https://github.com/cloudflare/workers-sdk/issues/new/choose + + " `); + expect(normalizeOutput(std.out)).toMatchInlineSnapshot(`"Deleting Pipeline bad-pipeline."`); expect(requests.count).toEqual(1); }); }); diff --git a/packages/wrangler/src/__tests__/queues.test.ts b/packages/wrangler/src/__tests__/queues.test.ts index 43c19fb4f9f..3c6473dda72 100644 --- a/packages/wrangler/src/__tests__/queues.test.ts +++ b/packages/wrangler/src/__tests__/queues.test.ts @@ -319,18 +319,10 @@ describe("wrangler", () => { runWrangler(`queues create ${queueName}`) ).rejects.toThrowError(); expect(std.out).toMatchInlineSnapshot(` - "🌀 Creating queue 'testQueue' - Queues is not currently enabled on this account. Go to https://dash.cloudflare.com/some-account-id/workers/queues to enable it. - - X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/queues) failed. - - workers.api.error.unauthorized [code: 10023] - - If you think this is a bug, please open an issue at: - https://github.com/cloudflare/workers-sdk/issues/new/choose - - " - `); + "🌀 Creating queue 'testQueue' + Queues is not currently enabled on this account. Go to https://dash.cloudflare.com/some-account-id/workers/queues to enable it. + " + `); }); it("should show an error when two delivery delays are set", async () => { diff --git a/packages/wrangler/src/__tests__/secret.test.ts b/packages/wrangler/src/__tests__/secret.test.ts index c7766f045a1..51586072691 100644 --- a/packages/wrangler/src/__tests__/secret.test.ts +++ b/packages/wrangler/src/__tests__/secret.test.ts @@ -1106,7 +1106,8 @@ describe("wrangler secret", () => { "info": "", "out": " ⛅️ wrangler x.x.x - ────────────────── + ------------------ + 🌀 Creating the secrets for the Worker \\"script-name\\" 🚨 Secrets failed to upload diff --git a/packages/wrangler/src/__tests__/sentry.test.ts b/packages/wrangler/src/__tests__/sentry.test.ts index d1e83c9a496..0bcd7d0be0f 100644 --- a/packages/wrangler/src/__tests__/sentry.test.ts +++ b/packages/wrangler/src/__tests__/sentry.test.ts @@ -268,22 +268,22 @@ describe("sentry", () => { Object { "colno": 0, "context_line": "", - "filename": "/wrangler/packages/wrangler/src/user/commands.ts", + "filename": "/wrangler/packages/wrangler/src/core/register-yargs-command.ts", "function": "", "in_app": false, "lineno": 0, - "module": "commands.ts", + "module": "register-yargs-command.ts", "post_context": Array [], "pre_context": Array [], }, Object { "colno": 0, "context_line": "", - "filename": "/wrangler/packages/wrangler/src/user/whoami.ts", + "filename": "/wrangler/packages/wrangler/src/user/commands.ts", "function": "", "in_app": false, "lineno": 0, - "module": "whoami.ts", + "module": "commands.ts", "post_context": Array [], "pre_context": Array [], }, @@ -312,22 +312,22 @@ describe("sentry", () => { Object { "colno": 0, "context_line": "", - "filename": "/wrangler/packages/wrangler/src/cfetch/index.ts", + "filename": "/wrangler/packages/wrangler/src/user/whoami.ts", "function": "", "in_app": false, "lineno": 0, - "module": "index.ts", + "module": "whoami.ts", "post_context": Array [], "pre_context": Array [], }, Object { "colno": 0, "context_line": "", - "filename": "/wrangler/packages/wrangler/src/cfetch/internal.ts", + "filename": "/wrangler/packages/wrangler/src/cfetch/index.ts", "function": "", "in_app": false, "lineno": 0, - "module": "internal.ts", + "module": "index.ts", "post_context": Array [], "pre_context": Array [], }, @@ -345,11 +345,11 @@ describe("sentry", () => { Object { "colno": 0, "context_line": "", - "filename": "node:internal/process/task_queues", + "filename": "/wrangler/packages/wrangler/src/cfetch/internal.ts", "function": "", "in_app": false, "lineno": 0, - "module": "task_queues", + "module": "internal.ts", "post_context": Array [], "pre_context": Array [], }, From 0e8491291c842fcbfda1df8d174bdc6bab78d5e7 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Mon, 29 Sep 2025 13:29:18 +0100 Subject: [PATCH 5/6] fix tests --- .../wrangler/src/__tests__/deploy.test.ts | 41 +++++++++++++++++-- .../wrangler/src/__tests__/pipelines.test.ts | 8 +++- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/wrangler/src/__tests__/deploy.test.ts b/packages/wrangler/src/__tests__/deploy.test.ts index 0175a7818fc..6e82d02e3e4 100644 --- a/packages/wrangler/src/__tests__/deploy.test.ts +++ b/packages/wrangler/src/__tests__/deploy.test.ts @@ -11692,9 +11692,44 @@ export default{ main: "index.js", }); - await expect(runWrangler("deploy")).rejects.toThrowError( - `Your Worker failed validation because it exceeded startup limits.` - ); + await expect(runWrangler("deploy")).rejects.toThrowError(); + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "X [ERROR] Your Worker failed validation because it exceeded startup limits. + + + A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) + failed. + - Error: Script startup exceeded CPU time limit. [code: 10021] + + To ensure fast responses, there are constraints on Worker startup, such as how much CPU it can + use, or how long it can take. Your Worker has hit one of these startup limits. Try reducing the + amount of work done during startup (outside the event handler), either by removing code or + relocating it inside the event handler. + + Refer to https://developers.cloudflare.com/workers/platform/limits/#worker-startup-time for more + details + A CPU Profile of your Worker's startup phase has been written to + .wrangler/tmp/startup-profile-/worker.cpuprofile - load it into the Chrome DevTools profiler + (or directly in VSCode) to view a flamegraph. + + + X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/scripts/test-name/versions) failed. + + Error: Script startup exceeded CPU time limit. [code: 10021] + + If you think this is a bug, please open an issue at: + https://github.com/cloudflare/workers-sdk/issues/new/choose + + ", + "info": "", + "out": "Total Upload: xx KiB / gzip: xx KiB + No bindings found. + ", + "warn": "", + } + `); }); describe("unit tests", () => { diff --git a/packages/wrangler/src/__tests__/pipelines.test.ts b/packages/wrangler/src/__tests__/pipelines.test.ts index 7e806e3a84c..ae710506445 100644 --- a/packages/wrangler/src/__tests__/pipelines.test.ts +++ b/packages/wrangler/src/__tests__/pipelines.test.ts @@ -472,7 +472,9 @@ describe("pipelines", () => { " `); - expect(normalizeOutput(std.out)).toMatchInlineSnapshot(`"Retrieving config for Pipeline \\"bad-pipeline\\"."`); + expect(normalizeOutput(std.out)).toMatchInlineSnapshot( + `"Retrieving config for Pipeline \\"bad-pipeline\\"."` + ); expect(requests.count).toEqual(1); }); }); @@ -644,7 +646,9 @@ describe("pipelines", () => { " `); - expect(normalizeOutput(std.out)).toMatchInlineSnapshot(`"Deleting Pipeline bad-pipeline."`); + expect(normalizeOutput(std.out)).toMatchInlineSnapshot( + `"Deleting Pipeline bad-pipeline."` + ); expect(requests.count).toEqual(1); }); }); From 47d639ceb4a59cd8b636d3120cad264eff313b17 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Mon, 29 Sep 2025 16:03:04 +0100 Subject: [PATCH 6/6] drop sentry --- .../wrangler/src/__tests__/sentry.test.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/wrangler/src/__tests__/sentry.test.ts b/packages/wrangler/src/__tests__/sentry.test.ts index 0bcd7d0be0f..d1e83c9a496 100644 --- a/packages/wrangler/src/__tests__/sentry.test.ts +++ b/packages/wrangler/src/__tests__/sentry.test.ts @@ -268,22 +268,22 @@ describe("sentry", () => { Object { "colno": 0, "context_line": "", - "filename": "/wrangler/packages/wrangler/src/core/register-yargs-command.ts", + "filename": "/wrangler/packages/wrangler/src/user/commands.ts", "function": "", "in_app": false, "lineno": 0, - "module": "register-yargs-command.ts", + "module": "commands.ts", "post_context": Array [], "pre_context": Array [], }, Object { "colno": 0, "context_line": "", - "filename": "/wrangler/packages/wrangler/src/user/commands.ts", + "filename": "/wrangler/packages/wrangler/src/user/whoami.ts", "function": "", "in_app": false, "lineno": 0, - "module": "commands.ts", + "module": "whoami.ts", "post_context": Array [], "pre_context": Array [], }, @@ -312,22 +312,22 @@ describe("sentry", () => { Object { "colno": 0, "context_line": "", - "filename": "/wrangler/packages/wrangler/src/user/whoami.ts", + "filename": "/wrangler/packages/wrangler/src/cfetch/index.ts", "function": "", "in_app": false, "lineno": 0, - "module": "whoami.ts", + "module": "index.ts", "post_context": Array [], "pre_context": Array [], }, Object { "colno": 0, "context_line": "", - "filename": "/wrangler/packages/wrangler/src/cfetch/index.ts", + "filename": "/wrangler/packages/wrangler/src/cfetch/internal.ts", "function": "", "in_app": false, "lineno": 0, - "module": "index.ts", + "module": "internal.ts", "post_context": Array [], "pre_context": Array [], }, @@ -345,11 +345,11 @@ describe("sentry", () => { Object { "colno": 0, "context_line": "", - "filename": "/wrangler/packages/wrangler/src/cfetch/internal.ts", + "filename": "node:internal/process/task_queues", "function": "", "in_app": false, "lineno": 0, - "module": "internal.ts", + "module": "task_queues", "post_context": Array [], "pre_context": Array [], },