From 294fdbd04604f22a5dba2bfed7cb2a9f4b50e478 Mon Sep 17 00:00:00 2001 From: Izaak Gough Date: Fri, 16 Oct 2026 13:03:24 +0100 Subject: [PATCH] fix(hosting): name the function and regions in the wrong-region rewrite error --- CHANGELOG.md | 1 + src/deploy/hosting/convertConfig.spec.ts | 78 +++++++++++++++++++++++- src/deploy/hosting/convertConfig.ts | 28 ++++----- 3 files changed, 89 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1192375095..b780ce45b41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ - Ensured the Firebase Hosting API is enabled before deploying and running other Hosting commands. +- Improved the error shown when a Hosting rewrite targets a function in the wrong region. It now names the function, the rewrite region, and the regions where the function was found. (#11289) diff --git a/src/deploy/hosting/convertConfig.spec.ts b/src/deploy/hosting/convertConfig.spec.ts index 6fb42a54c4b..8f824f670cd 100644 --- a/src/deploy/hosting/convertConfig.spec.ts +++ b/src/deploy/hosting/convertConfig.spec.ts @@ -535,7 +535,83 @@ describe("convertConfig", () => { version: "14", }, ), - ).to.eventually.be.rejectedWith(FirebaseError); + ).to.eventually.be.rejectedWith( + FirebaseError, + `Rewrite for function \`${FUNCTION_ID}\` in firebase.json targets region \`asia-northeast1\`, ` + + `but \`${FUNCTION_ID}\` was only found in \`europe-west1\`. Update the rewrite's \`region\` ` + + `in firebase.json to that region.`, + ); + }); + it("should name the deployed region when rewrite points to an existing function in the wrong region", async () => { + existingBackendStub.resolves( + backend.of({ + id: FUNCTION_ID, + project: PROJECT_ID, + entryPoint: FUNCTION_ID, + runtime: "nodejs22", + region: "europe-west1", + platform: "gcfv2", + httpsTrigger: {}, + }), + ); + await expect( + convertConfig( + { projectId: "1" }, + {}, + { + config: { + site: "foo", + rewrites: [ + { glob: "/foo", function: { functionId: FUNCTION_ID, region: "us-central1" } }, + ], + }, + version: "14", + }, + ), + ).to.eventually.be.rejectedWith( + FirebaseError, + `Rewrite for function \`${FUNCTION_ID}\` in firebase.json targets region \`us-central1\`, ` + + `but \`${FUNCTION_ID}\` was only found in \`europe-west1\`. Update the rewrite's \`region\` ` + + `in firebase.json to that region.`, + ); + }); + it("should list every region when rewrite matches none of a multi-region function", async () => { + const endpointIn = (region: string): backend.Endpoint => ({ + id: FUNCTION_ID, + project: PROJECT_ID, + entryPoint: FUNCTION_ID, + runtime: "nodejs22", + region, + platform: "gcfv2", + httpsTrigger: {}, + }); + await expect( + convertConfig( + { projectId: "1" }, + { + functions: { + default: { + wantBackend: backend.of(endpointIn("europe-west1"), endpointIn("us-east1")), + haveBackend: backend.empty(), + }, + }, + }, + { + config: { + site: "foo", + rewrites: [ + { glob: "/foo", function: { functionId: FUNCTION_ID, region: "asia-northeast1" } }, + ], + }, + version: "14", + }, + ), + ).to.eventually.be.rejectedWith( + FirebaseError, + `Rewrite for function \`${FUNCTION_ID}\` in firebase.json targets region \`asia-northeast1\`, ` + + `but \`${FUNCTION_ID}\` was only found in \`europe-west1\`, \`us-east1\`. Update the rewrite's ` + + `\`region\` in firebase.json to one of these regions.`, + ); }); it("should throw when rewrite points to function being deleted", async () => { await expect( diff --git a/src/deploy/hosting/convertConfig.ts b/src/deploy/hosting/convertConfig.ts index 8c484b9facd..81968149714 100644 --- a/src/deploy/hosting/convertConfig.ts +++ b/src/deploy/hosting/convertConfig.ts @@ -61,10 +61,7 @@ export function findEndpointForRewrite( if (endpoints.length === 0) { return { matchingEndpoint: undefined, foundMatchingId: false }; } - if (endpoints.length === 1) { - if (region && region !== endpoints[0].region) { - return { matchingEndpoint: undefined, foundMatchingId: true }; - } + if (!region && endpoints.length === 1) { return { matchingEndpoint: endpoints[0], foundMatchingId: true }; } if (!region) { @@ -81,10 +78,16 @@ export function findEndpointForRewrite( ); return { matchingEndpoint: us, foundMatchingId: true }; } - return { - matchingEndpoint: endpoints.find((e) => e.region === region), - foundMatchingId: true, - }; + const matchingEndpoint = endpoints.find((e) => e.region === region); + if (!matchingEndpoint) { + const regions = endpoints.map((e) => `\`${e.region}\``).join(", "); + throw new FirebaseError( + `Rewrite for function \`${id}\` in firebase.json targets region \`${region}\`, ` + + `but \`${id}\` was only found in ${regions}. Update the rewrite's \`region\` ` + + `in firebase.json to ${endpoints.length === 1 ? "that region" : "one of these regions"}.`, + ); + } + return { matchingEndpoint, foundMatchingId: true }; } /** @@ -165,15 +168,6 @@ export async function convertConfig( : existingEndpointSearch?.matchingEndpoint; if (!endpoint) { - // If we find a function matching the function ID we are looking for in either - // existing or currently-deploying backends, we consider it a firebase function. - // In this case, we throw an error if the rewrite doesn't point to a valid region. - if (deployingEndpointSearch.foundMatchingId || existingEndpointSearch?.foundMatchingId) { - throw new FirebaseError( - `Unable to find a valid endpoint for function. Functions matching the rewrite - are present but in the wrong region.`, - ); - } // This could possibly succeed if there has been a function written // outside firebase tooling. But it will break in v2. We might need to // revisit this.