From 8e08b4d3f490838c1b98ac1aecf82680614e5a2c Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Wed, 3 Dec 2025 16:42:01 +0000 Subject: [PATCH 1/3] Introduce internal `isWorkerNotFoundError` utility and avoid worker-not-found error code magic numbers in wrangler --- .../wrangler/src/__tests__/secret.test.ts | 12 +++++--- packages/wrangler/src/deploy/deploy.ts | 9 +++--- packages/wrangler/src/durable.ts | 7 ++--- packages/wrangler/src/init.ts | 3 +- packages/wrangler/src/match-tag.ts | 4 +-- packages/wrangler/src/secret/index.ts | 13 ++------ .../src/utils/worker-not-found-error.ts | 30 +++++++++++++++++++ packages/wrangler/src/versions/deploy.ts | 6 ++-- packages/wrangler/src/versions/upload.ts | 5 ++-- 9 files changed, 57 insertions(+), 32 deletions(-) create mode 100644 packages/wrangler/src/utils/worker-not-found-error.ts diff --git a/packages/wrangler/src/__tests__/secret.test.ts b/packages/wrangler/src/__tests__/secret.test.ts index 238b5edc5905..cb2c6d8ac16d 100644 --- a/packages/wrangler/src/__tests__/secret.test.ts +++ b/packages/wrangler/src/__tests__/secret.test.ts @@ -5,6 +5,10 @@ import { http, HttpResponse } from "msw"; import * as TOML from "smol-toml"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { VERSION_NOT_DEPLOYED_ERR_CODE } from "../secret"; +import { + WORKER_NOT_FOUND_ERR_CODE, + workerNotFoundErrorMessage, +} from "../utils/worker-not-found-error"; import { mockAccountId, mockApiToken } from "./helpers/mock-account-id"; import { mockConsoleMethods } from "./helpers/mock-console"; import { clearDialogs, mockConfirm, mockPrompt } from "./helpers/mock-dialogs"; @@ -53,8 +57,8 @@ function mockNoWorkerFound(isBulk = false) { return HttpResponse.json( createFetchResult(null, false, [ { - code: 10007, - message: "This Worker does not exist on your account.", + code: WORKER_NOT_FOUND_ERR_CODE, + message: workerNotFoundErrorMessage, }, ]) ); @@ -70,8 +74,8 @@ function mockNoWorkerFound(isBulk = false) { return HttpResponse.json( createFetchResult(null, false, [ { - code: 10007, - message: "This Worker does not exist on your account.", + code: WORKER_NOT_FOUND_ERR_CODE, + message: workerNotFoundErrorMessage, }, ]) ); diff --git a/packages/wrangler/src/deploy/deploy.ts b/packages/wrangler/src/deploy/deploy.ts index 77960d5ef897..0c728ba30e83 100644 --- a/packages/wrangler/src/deploy/deploy.ts +++ b/packages/wrangler/src/deploy/deploy.ts @@ -64,6 +64,7 @@ import { helpIfErrorIsSizeOrScriptStartup } from "../utils/friendly-validator-er import { parseConfigPlacement } from "../utils/placement"; import { printBindings } from "../utils/print-bindings"; import { retryOnAPIFailure } from "../utils/retry"; +import { isWorkerNotFoundError } from "../utils/worker-not-found-error"; import { createDeployment, patchNonVersionedScriptSettings, @@ -463,12 +464,10 @@ export default async function deploy(props: Props): Promise<{ } } } catch (e) { - // code: 10090, message: workers.api.error.service_not_found - // is thrown from the above fetchResult on the first deploy of a Worker - if ((e as { code?: number }).code !== 10090) { - throw e; - } else { + if (isWorkerNotFoundError(e)) { workerExists = false; + } else { + throw e; } } } diff --git a/packages/wrangler/src/durable.ts b/packages/wrangler/src/durable.ts index 1096a6a06d60..5e939c440c76 100644 --- a/packages/wrangler/src/durable.ts +++ b/packages/wrangler/src/durable.ts @@ -2,6 +2,7 @@ import assert from "node:assert"; import { configFileName } from "@cloudflare/workers-utils"; import { fetchResult } from "./cfetch"; import { logger } from "./logger"; +import { isWorkerNotFoundError } from "./utils/worker-not-found-error"; import type { CfWorkerInit, Config } from "@cloudflare/workers-utils"; /** @@ -111,10 +112,8 @@ export async function getMigrationsToUpload( const suppressNotFoundError = (err: unknown) => { if ( - ![ - 10090, // corresponds to workers.api.error.service_not_found, so the script wasn't previously published at all - 10092, // workers.api.error.environment_not_found, so the script wasn't published to this environment yet - ].includes((err as { code: number }).code) + !isWorkerNotFoundError(err) && + (err as { code: number }).code !== 10092 // workers.api.error.environment_not_found, so the script wasn't published to this environment yet ) { throw err; } diff --git a/packages/wrangler/src/init.ts b/packages/wrangler/src/init.ts index a27159d3b08c..f6fefabe5bd5 100644 --- a/packages/wrangler/src/init.ts +++ b/packages/wrangler/src/init.ts @@ -17,6 +17,7 @@ import { requireAuth } from "./user"; import { createBatches } from "./utils/create-batches"; import { downloadWorkerConfig } from "./utils/download-worker-config"; import * as shellquote from "./utils/shell-quote"; +import { isWorkerNotFoundError } from "./utils/worker-not-found-error"; import type { PackageManager } from "./package-manager"; import type { ServiceMetadataRes } from "@cloudflare/workers-utils"; import type { ReadableStream } from "node:stream/web"; @@ -83,7 +84,7 @@ export const init = createCommand({ `/accounts/${accountId}/workers/services/${args.fromDash}` ); } catch (err) { - if ((err as { code?: number }).code === 10090) { + if (isWorkerNotFoundError(err)) { throw new UserError( "wrangler couldn't find a Worker with that name in your account.\nRun `wrangler whoami` to confirm you're logged into the correct account.", { diff --git a/packages/wrangler/src/match-tag.ts b/packages/wrangler/src/match-tag.ts index de5a1ca393b6..97d91e859a2f 100644 --- a/packages/wrangler/src/match-tag.ts +++ b/packages/wrangler/src/match-tag.ts @@ -8,6 +8,7 @@ import { import { fetchResult } from "./cfetch"; import { logger } from "./logger"; import { getCloudflareAccountIdFromEnv } from "./user/auth-variables"; +import { isWorkerNotFoundError } from "./utils/worker-not-found-error"; import type { ComplianceConfig, ServiceMetadataRes, @@ -52,8 +53,7 @@ export async function verifyWorkerMatchesCITag( logger.debug(`API returned with tag: ${tag} for worker: ${workerName}`); } catch (e) { logger.debug(e); - // code: 10090, message: workers.api.error.service_not_found - if ((e as { code?: number }).code === 10090) { + if (isWorkerNotFoundError(e)) { throw new FatalError( `The name in your ${configFileName(configPath)} file (${workerName}) must match the name of your Worker. Please update the name field in your ${configFileName(configPath)} file.` ); diff --git a/packages/wrangler/src/secret/index.ts b/packages/wrangler/src/secret/index.ts index 39c4eeb51847..8554057e39fc 100644 --- a/packages/wrangler/src/secret/index.ts +++ b/packages/wrangler/src/secret/index.ts @@ -21,6 +21,7 @@ import { fetchSecrets } from "../utils/fetch-secrets"; import { getLegacyScriptName } from "../utils/getLegacyScriptName"; import { readFromStdin, trimTrailingWhitespace } from "../utils/std"; import { useServiceEnvironments } from "../utils/useServiceEnvironments"; +import { isWorkerNotFoundError } from "../utils/worker-not-found-error"; import type { Config, WorkerMetadataBinding } from "@cloudflare/workers-utils"; export const VERSION_NOT_DEPLOYED_ERR_CODE = 10215; @@ -38,14 +39,6 @@ type InheritBindingUpload = { type SecretBindingRedacted = Omit; -function isMissingWorkerError(e: unknown): e is { code: 10007 } { - return ( - typeof e === "object" && - e !== null && - (e as { code: number }).code === 10007 - ); -} - async function createDraftWorker({ config, args, @@ -239,7 +232,7 @@ export const secretPutCommand = createCommand({ sendMetrics: config.send_metrics, }); } catch (e) { - if (isMissingWorkerError(e)) { + if (isWorkerNotFoundError(e)) { // create a draft worker and try again const result = await createDraftWorker({ config, @@ -486,7 +479,7 @@ export const secretBulkCommand = createCommand({ const settings = await getSettings(); existingBindings = settings.bindings; } catch (e) { - if (isMissingWorkerError(e)) { + if (isWorkerNotFoundError(e)) { // create a draft worker before patching const result = await createDraftWorker({ config, diff --git a/packages/wrangler/src/utils/worker-not-found-error.ts b/packages/wrangler/src/utils/worker-not-found-error.ts new file mode 100644 index 000000000000..8ddb115b6bb9 --- /dev/null +++ b/packages/wrangler/src/utils/worker-not-found-error.ts @@ -0,0 +1,30 @@ +/** + This is the error code from the Cloudflare API signaling that a worker could not be found on the target account + */ +export const WORKER_NOT_FOUND_ERR_CODE = 10007 as const; + +/** + This is the error code from the Cloudflare API signaling that a worker environment (legacy) could not be found on the target account + */ +export const WORKER_LEGACY_ENVIRONMENT_NOT_FOUND_ERR_CODE = 10090 as const; + +/** + This is the error message from the Cloudflare API signaling that a worker could not be found on the target account + */ +export const workerNotFoundErrorMessage = + "This Worker does not exist on your account."; + +/** + * Given an error from the Cloudflare API discerns wether it is caused by a worker that could not be found on the target account + * + * @param error The error object + * @returns true is the object represents an error from the Cloudflare API caused by a not found worker, false otherwise + */ +export function isWorkerNotFoundError(error: unknown): boolean { + return ( + error instanceof Object && + "code" in error && + (error.code === WORKER_NOT_FOUND_ERR_CODE || + error.code === WORKER_LEGACY_ENVIRONMENT_NOT_FOUND_ERR_CODE) + ); +} diff --git a/packages/wrangler/src/versions/deploy.ts b/packages/wrangler/src/versions/deploy.ts index ec8ac22b5bcc..397cdff7f2e8 100644 --- a/packages/wrangler/src/versions/deploy.ts +++ b/packages/wrangler/src/versions/deploy.ts @@ -7,7 +7,7 @@ import { leftT, spinnerWhile, } from "@cloudflare/cli/interactive"; -import { APIError, UserError } from "@cloudflare/workers-utils"; +import { UserError } from "@cloudflare/workers-utils"; import { fetchResult } from "../cfetch"; import { createCommand } from "../core/create-command"; import { isNonInteractiveOrCI } from "../is-interactive"; @@ -15,6 +15,7 @@ import * as metrics from "../metrics"; import { writeOutput } from "../output"; import { requireAuth } from "../user"; import formatLabelledValues from "../utils/render-labelled-values"; +import { isWorkerNotFoundError } from "../utils/worker-not-found-error"; import { createDeployment, fetchDeployableVersions, @@ -263,8 +264,7 @@ export async function confirmLatestDeploymentOverwrite( }); } } catch (e) { - const isNotFound = e instanceof APIError && e.code == 10007; - if (!isNotFound) { + if (!isWorkerNotFoundError(e)) { throw e; } } diff --git a/packages/wrangler/src/versions/upload.ts b/packages/wrangler/src/versions/upload.ts index dbe7279d84d0..2619744b35da 100644 --- a/packages/wrangler/src/versions/upload.ts +++ b/packages/wrangler/src/versions/upload.ts @@ -65,6 +65,7 @@ import { parseConfigPlacement } from "../utils/placement"; import { printBindings } from "../utils/print-bindings"; import { retryOnAPIFailure } from "../utils/retry"; import { useServiceEnvironments } from "../utils/useServiceEnvironments"; +import { isWorkerNotFoundError } from "../utils/worker-not-found-error"; import { patchNonVersionedScriptSettings } from "./api"; import type { AssetsOptions } from "../assets"; import type { Entry } from "../deployment-bundle/entry"; @@ -460,9 +461,7 @@ export default async function versionsUpload(props: Props): Promise<{ } } } catch (e) { - // code: 10090, message: workers.api.error.service_not_found - // is thrown from the above fetchResult on the first deploy of a Worker - if ((e as { code?: number }).code !== 10090) { + if (!isWorkerNotFoundError(e)) { throw e; } } From 57dbbc297994d9beda3f02e0f415f085c6488642 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Tue, 9 Dec 2025 00:04:21 +0000 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Pete Bacon Darwin --- packages/wrangler/src/utils/worker-not-found-error.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/wrangler/src/utils/worker-not-found-error.ts b/packages/wrangler/src/utils/worker-not-found-error.ts index 8ddb115b6bb9..3a76f51575e7 100644 --- a/packages/wrangler/src/utils/worker-not-found-error.ts +++ b/packages/wrangler/src/utils/worker-not-found-error.ts @@ -15,14 +15,14 @@ export const workerNotFoundErrorMessage = "This Worker does not exist on your account."; /** - * Given an error from the Cloudflare API discerns wether it is caused by a worker that could not be found on the target account + * Given an error from the Cloudflare API discerns whether it is caused by a worker that could not be found on the target account * * @param error The error object - * @returns true is the object represents an error from the Cloudflare API caused by a not found worker, false otherwise + * @returns true if the object represents an error from the Cloudflare API caused by a not found worker, false otherwise */ export function isWorkerNotFoundError(error: unknown): boolean { return ( - error instanceof Object && + typeof error === "object" && error !== null && "code" in error && (error.code === WORKER_NOT_FOUND_ERR_CODE || error.code === WORKER_LEGACY_ENVIRONMENT_NOT_FOUND_ERR_CODE) From 3885e7fe8e3a691d5e4e3ae740c577c58b1f0627 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Tue, 9 Dec 2025 10:31:21 +0000 Subject: [PATCH 3/3] fix formatting --- packages/wrangler/src/utils/worker-not-found-error.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/wrangler/src/utils/worker-not-found-error.ts b/packages/wrangler/src/utils/worker-not-found-error.ts index 3a76f51575e7..dacb1e5ea644 100644 --- a/packages/wrangler/src/utils/worker-not-found-error.ts +++ b/packages/wrangler/src/utils/worker-not-found-error.ts @@ -22,7 +22,8 @@ export const workerNotFoundErrorMessage = */ export function isWorkerNotFoundError(error: unknown): boolean { return ( - typeof error === "object" && error !== null && + typeof error === "object" && + error !== null && "code" in error && (error.code === WORKER_NOT_FOUND_ERR_CODE || error.code === WORKER_LEGACY_ENVIRONMENT_NOT_FOUND_ERR_CODE)