From 835e5f806e92ce562aa3c4c6b8f1f849390834b2 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Tue, 23 Sep 2025 14:58:59 +0100 Subject: [PATCH 1/5] Improve error logging --- .../src/__tests__/cfetch-utils.test.ts | 15 ++-- .../wrangler/src/__tests__/deploy.test.ts | 36 ++++---- .../__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 | 25 +++--- .../wrangler/src/api/startDevWorker/DevEnv.ts | 4 +- packages/wrangler/src/dev/remote.ts | 83 ++++++++++--------- packages/wrangler/src/index.ts | 8 +- packages/wrangler/src/logger.ts | 21 ++++- packages/wrangler/src/utils/isAbortError.ts | 2 +- 13 files changed, 172 insertions(+), 115 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 8c2f844a9f0..c40a825a66e 100644 --- a/packages/wrangler/src/__tests__/deploy.test.ts +++ b/packages/wrangler/src/__tests__/deploy.test.ts @@ -464,13 +464,16 @@ describe("deploy", () => { ).rejects.toThrowErrorMatchingInlineSnapshot( `[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. + expect(std).toMatchInlineSnapshot(` + Object { + "debug": "", + "err": "X [ERROR] A request to the Cloudflare API (/accounts/some-account-id/workers/services/test-name) failed. Authentication error [code: 10000] - + ", + "info": "", + "out": " 📎 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. @@ -486,7 +489,9 @@ describe("deploy", () => { ├─┼─┤ │ Account Three │ account-3 │ └─┴─┘ - 🔓 To see token permissions visit https://dash.cloudflare.com/profile/api-tokens." + 🔓 To see token permissions visit https://dash.cloudflare.com/profile/api-tokens.", + "warn": "", + } `); }); @@ -11381,11 +11386,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] @@ -11393,6 +11394,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": "", } @@ -11469,9 +11473,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. @@ -11480,6 +11481,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": "", } @@ -11544,9 +11548,6 @@ export default{ .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. @@ -11555,6 +11556,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": "", } diff --git a/packages/wrangler/src/__tests__/pages/functions-build.test.ts b/packages/wrangler/src/__tests__/pages/functions-build.test.ts index d3b51dbac71..8ebc793ce63 100644 --- a/packages/wrangler/src/__tests__/pages/functions-build.test.ts +++ b/packages/wrangler/src/__tests__/pages/functions-build.test.ts @@ -1172,6 +1172,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 3c4f62a2d40..860fe0795c5 100644 --- a/packages/wrangler/src/__tests__/r2.test.ts +++ b/packages/wrangler/src/__tests__/r2.test.ts @@ -448,17 +448,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": "", + } `); }); }); @@ -536,17 +541,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 45d7c58aea3..cbc12d35414 100644 --- a/packages/wrangler/src/__tests__/secret.test.ts +++ b/packages/wrangler/src/__tests__/secret.test.ts @@ -1186,22 +1186,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 31cbea97372..5ce1be9a8fb 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, runWithLogLevel } from "../../logger"; -import { formatMessage, ParseError } from "../../parse"; +import { ParseError } from "../../parse"; import { BundlerController } from "./BundlerController"; import { ConfigController } from "./ConfigController"; import { LocalRuntimeController } from "./LocalRuntimeController"; @@ -137,7 +137,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 21c8ed2ea41..7a0cf734742 100644 --- a/packages/wrangler/src/dev/remote.ts +++ b/packages/wrangler/src/dev/remote.ts @@ -7,6 +7,7 @@ import { withSourceURLs } from "../deployment-bundle/source-url"; import { getInferredHost } from "../dev"; import { UserError } from "../errors"; import { logger } from "../logger"; +import { APIError } from "../parse"; import { syncWorkersSite } from "../sites"; import { requireApiToken } from "../user"; import { isAbortError } from "../utils/isAbortError"; @@ -20,7 +21,6 @@ import type { 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 { ApiCredentials } from "../user"; import type { CfAccount } from "./create-worker-preview"; @@ -35,7 +35,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"); @@ -44,7 +44,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); } } @@ -78,7 +78,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); } } @@ -241,49 +241,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 6e13c4fc1e3..ab33e4e5876 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -147,7 +147,7 @@ import { } from "./pages/secret"; import { pagesProjectUploadCommand } from "./pages/upload"; import { pagesProjectValidateCommand } from "./pages/validate"; -import { APIError, formatMessage, ParseError } from "./parse"; +import { APIError, ParseError } from "./parse"; import { pipelinesNamespace } from "./pipelines"; import { pipelinesCreateCommand } from "./pipelines/cli/create"; import { pipelinesDeleteCommand } from "./pipelines/cli/delete"; @@ -1677,7 +1677,7 @@ export async function main(argv: string[]): Promise { logger.error(e.cause); } else { assert(isAuthenticationError(e)); - logger.log(formatMessage(e)); + logger.error(e); } const envAuth = getAuthFromEnv(); if (envAuth !== undefined && "apiToken" in envAuth) { @@ -1700,7 +1700,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 ( @@ -1747,7 +1747,7 @@ export async function main(argv: string[]): Promise { error.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(error)); + logger.error(error); } else { if ( // Is this a StartDevEnv error event? If so, unwrap the cause, which is usually the user-recognisable error diff --git a/packages/wrangler/src/logger.ts b/packages/wrangler/src/logger.ts index 2b59700505e..294937be28b 100644 --- a/packages/wrangler/src/logger.ts +++ b/packages/wrangler/src/logger.ts @@ -5,6 +5,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"; @@ -121,7 +122,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[], options?: { wordWrap: boolean; head?: Keys[] } @@ -185,8 +195,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 7e2127b69d689bdb899c5ce179dd72ca56614646 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/5] 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 c36561cd0ceb7a8a8f82a8fa21d914b4e36a488d Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 24 Sep 2025 17:26:42 +0100 Subject: [PATCH 3/5] fix secrets store e2e tests --- packages/wrangler/e2e/secrets-store.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/wrangler/e2e/secrets-store.test.ts b/packages/wrangler/e2e/secrets-store.test.ts index f8696cb23ce..21e7c9a21f6 100644 --- a/packages/wrangler/e2e/secrets-store.test.ts +++ b/packages/wrangler/e2e/secrets-store.test.ts @@ -148,7 +148,7 @@ describe.each(RUNTIMES)( "🔐 Getting secret... (ID: 00000000000000000000000000000000)" ); if (runtime === "remote") { - expect(normalize(output.stdout)).toContain( + expect(normalize(output.stderr)).toContain( "secret_not_found [code: 1001]" ); } else { @@ -180,7 +180,7 @@ describe.each(RUNTIMES)( expect(normalize(output.stdout)).toContain( "🔐 Getting secret... (ID: 00000000000000000000000000000000)" ); - expect(normalize(output.stdout)).toContain( + expect(normalize(output.stderr)).toContain( "store_not_found [code: 1001]" ); }); From d0cf7cbcba280a61467f09d383a548636602c490 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Mon, 29 Sep 2025 16:29:00 +0100 Subject: [PATCH 4/5] inline error messages --- packages/wrangler/src/dev/remote.ts | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/packages/wrangler/src/dev/remote.ts b/packages/wrangler/src/dev/remote.ts index 7a0cf734742..1d5db572deb 100644 --- a/packages/wrangler/src/dev/remote.ts +++ b/packages/wrangler/src/dev/remote.ts @@ -1,5 +1,6 @@ import assert from "node:assert"; import path from "node:path"; +import dedent from "ts-dedent"; import { syncAssets } from "../assets"; import { printBundleSize } from "../deployment-bundle/bundle-reporter"; import { getBundleType } from "../deployment-bundle/bundle-type"; @@ -60,12 +61,9 @@ export function handlePreviewSessionCreationError( // give them friendly instructions // for error 10063 (workers.dev subdomain required) if ("code" in err && err.code === 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 = `https://dash.cloudflare.com/${accountId}/workers/onboarding`; - logger.error(`${errorMessage}\n${solutionMessage}\n${onboardingLink}`); + logger.error( + `You need to register a workers.dev subdomain before running the dev command in remote mode. You can either enable local mode by pressing l, or register a workers.dev subdomain here: https://dash.cloudflare.com/${accountId}/workers/onboarding` + ); } else if ( "cause" in err && (err.cause as { code: string; hostname: string })?.code === "ENOTFOUND" @@ -252,14 +250,8 @@ function handleUserFriendlyError(error: unknown, accountId?: string) { 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}` + `You must use a real database in the preview_database_id configuration. You can find your databases using 'wrangler d1 list', or read how to develop locally with D1 here: https://developers.cloudflare.com/d1/configuration/local-development` ); return true; @@ -270,15 +262,13 @@ function handleUserFriendlyError(error: unknown, accountId?: string) { // 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( + `You need to register a workers.dev subdomain before running the dev command in remote mode. You can either enable local mode by pressing l, or register a workers.dev subdomain here: ${onboardingLink}` + ); return true; } From 46d8a85988fc7d71cef7b836ae3c92252420e1b5 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Mon, 29 Sep 2025 16:47:54 +0100 Subject: [PATCH 5/5] fix lint --- packages/wrangler/src/dev/remote.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/wrangler/src/dev/remote.ts b/packages/wrangler/src/dev/remote.ts index 1d5db572deb..cfb4d64fecc 100644 --- a/packages/wrangler/src/dev/remote.ts +++ b/packages/wrangler/src/dev/remote.ts @@ -1,6 +1,5 @@ import assert from "node:assert"; import path from "node:path"; -import dedent from "ts-dedent"; import { syncAssets } from "../assets"; import { printBundleSize } from "../deployment-bundle/bundle-reporter"; import { getBundleType } from "../deployment-bundle/bundle-type";