Skip to content

Commit 1d685cb

Browse files
Ensure that wrangler dev and vite dev/preview crash when we fail to create a remote proxy session (#11383)
* Fix: ensure that when a remote proxy session (for remote bindings) cannot be established an appropriate error is surfaced to the user * Ensure that also the vite plugin crashes * Apply suggestions from code review Co-authored-by: Victor Berchet <[email protected]> * update changesets * remote unnecessary R2 in test * update tests and functionality * update `get-platform-proxy-remote-bindings` fixture tests * Update .changeset/proud-socks-slide.md Co-authored-by: Victor Berchet <[email protected]> * fix snapshot not working on Windows * update comment * remove duplicated changeset line --------- Co-authored-by: Victor Berchet <[email protected]>
1 parent 9a1de61 commit 1d685cb

File tree

17 files changed

+325
-140
lines changed

17 files changed

+325
-140
lines changed

.changeset/proud-socks-slide.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
"@cloudflare/vite-plugin": patch
3+
---
4+
5+
Fix: Ensure that `vite dev` and `vite preview` hard error with an appropriate error message when a remote proxy session is required but it the connection with it fails to be established
6+
7+
When using remote bindings, either with `vite dev` or `vite preview` the remote proxy session necessary to connect to the remote resources can fail to be created, this might happen if for example you try to set a binding with some invalid values such as:
8+
9+
```js
10+
MY_R2: {
11+
type: "r2_bucket",
12+
bucket_name: "non-existent", // No bucket called "non-existent" exists
13+
remote: true,
14+
},
15+
```
16+
17+
Before this could go undetected and cause unwanted behaviors such as requests handling hanging indefinitely, now a hard error will be thrown instead causing the vite process to crash, clearly indicating that something went wrong during the remote session's creation.

.changeset/stale-hats-hug.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
Fix: ensure that when a remote proxy session creation fails a hard error is surfaced to the user (both in `wrangler dev` and in the programmatic API).
6+
7+
When using remote bindings, either with `wrangler dev` or via `startRemoteProxySession`/`maybeStartOrUpdateRemoteProxySession` the remote proxy session necessary to connect to the remote resources can fail to be created, this might happen if for example you try to set a binding with some invalid values such as:
8+
9+
```js
10+
MY_R2: {
11+
type: "r2_bucket",
12+
bucket_name: "non-existent", // No bucket called "non-existent" exists
13+
remote: true,
14+
},
15+
```
16+
17+
Before this could go undetected and cause unwanted behaviors such as requests handling hanging indefinitely, now wrangler will instead crash (or throw a hard error ion the programmatic API), clearly indicating that something went wrong during the remote session's creation.

fixtures/get-platform-proxy-remote-bindings/tests/index.test.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@ import { execSync } from "child_process";
22
import { randomUUID } from "crypto";
33
import assert from "node:assert";
44
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
5-
import { afterAll, beforeAll, describe, expect, test, vi } from "vitest";
5+
import {
6+
afterAll,
7+
beforeAll,
8+
beforeEach,
9+
describe,
10+
expect,
11+
test,
12+
vi,
13+
} from "vitest";
614
import { getPlatformProxy } from "wrangler";
715
import type { KVNamespace } from "@cloudflare/workers-types/experimental";
816
import type { DispatchFetch, Response } from "miniflare";
@@ -18,6 +26,8 @@ const remoteWorkerName = `preserve-e2e-get-platform-proxy-remote`;
1826
const remoteStagingWorkerName = `preserve-e2e-get-platform-proxy-remote-staging`;
1927
const remoteKvName = `tmp-e2e-kv${Date.now()}-test-remote-bindings-${randomUUID().split("-")[0]}`;
2028

29+
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
30+
2131
if (auth) {
2232
describe("getPlatformProxy - remote bindings", { timeout: 50_000 }, () => {
2333
let remoteKvId: string;
@@ -97,6 +107,10 @@ if (auth) {
97107
} catch {}
98108
}, 35_000);
99109

110+
beforeEach(() => {
111+
errorSpy.mockReset();
112+
});
113+
100114
describe("normal usage", () => {
101115
beforeAll(async () => {
102116
mkdirSync("./.tmp/normal-usage");
@@ -223,17 +237,27 @@ if (auth) {
223237
"utf8"
224238
);
225239

226-
const { env, dispose } = await getPlatformProxy<{
227-
MY_WORKER: Fetcher;
228-
}>({
229-
configPath: "./.tmp/config-with-invalid-account-id/wrangler.json",
230-
});
231-
232-
const response = await fetchFromWorker(env.MY_WORKER, "OK", 10_000);
233-
// The worker does not return a response
234-
expect(response).toBe(undefined);
240+
await expect(
241+
getPlatformProxy<{
242+
MY_WORKER: Fetcher;
243+
}>({
244+
configPath: "./.tmp/config-with-invalid-account-id/wrangler.json",
245+
})
246+
).rejects.toMatchInlineSnapshot(
247+
`[Error: Failed to start the remote proxy session. There is likely additional logging output above.]`
248+
);
235249

236-
await dispose();
250+
expect(errorSpy).toHaveBeenCalledOnce();
251+
expect(
252+
`${errorSpy.mock.calls?.[0]?.[0]}`
253+
// Windows gets a different marker for ✘, so let's normalize it here
254+
// so that this test can be platform independent
255+
.replaceAll("✘", "X")
256+
).toMatchInlineSnapshot(`
257+
"X [ERROR] A request to the Cloudflare API (/accounts/NOT a valid account id/workers/subdomain/edge-preview) failed.
258+
259+
"
260+
`);
237261
});
238262

239263
test("usage with a wrangler config file with a valid account id", async () => {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "@cloudflare/vite-plugin-e2e-remote-bindings-incorrect-r2-config",
3+
"version": "0.0.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"build": "vite build",
8+
"buildAndPreview": "vite build && vite preview",
9+
"dev": "vite",
10+
"lint": "eslint .",
11+
"preview": "vite preview"
12+
},
13+
"devDependencies": {
14+
"@cloudflare/vite-plugin": "*",
15+
"@cloudflare/workers-types": "^4.20250204.0",
16+
"@eslint/js": "^9.19.0",
17+
"eslint": "^9.19.0",
18+
"eslint-plugin-react-hooks": "^5.0.0",
19+
"eslint-plugin-react-refresh": "^0.4.18",
20+
"globals": "^15.14.0",
21+
"typescript": "~5.7.2",
22+
"typescript-eslint": "^8.22.0",
23+
"vite": "^6.1.0"
24+
}
25+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default {
2+
async fetch() {
3+
return new Response("Hello");
4+
},
5+
} satisfies ExportedHandler;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"files": [],
3+
"references": [
4+
{ "path": "./tsconfig.node.json" },
5+
{ "path": "./tsconfig.worker.json" }
6+
]
7+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"compilerOptions": {
3+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4+
"target": "ES2022",
5+
"lib": ["ES2023"],
6+
"module": "ESNext",
7+
"skipLibCheck": true,
8+
9+
/* Bundler mode */
10+
"moduleResolution": "bundler",
11+
"allowImportingTsExtensions": true,
12+
"isolatedModules": true,
13+
"moduleDetection": "force",
14+
"noEmit": true,
15+
16+
/* Linting */
17+
"strict": true,
18+
"noUnusedLocals": true,
19+
"noUnusedParameters": true,
20+
"noFallthroughCasesInSwitch": true,
21+
"noUncheckedSideEffectImports": true
22+
},
23+
"include": ["vite.config.ts"]
24+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "./tsconfig.node.json",
3+
"compilerOptions": {
4+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo",
5+
"types": ["@cloudflare/workers-types/2023-07-01", "vite/client"]
6+
},
7+
"include": ["src"]
8+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { cloudflare } from "@cloudflare/vite-plugin";
2+
import { defineConfig } from "vite";
3+
4+
export default defineConfig({
5+
plugins: [
6+
cloudflare({
7+
configPath: "./wrangler.jsonc",
8+
inspectorPort: false,
9+
persistState: false,
10+
}),
11+
],
12+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "cloudflare-vite-e2e-remote-bindings-disabled",
3+
"main": "./src/index.ts",
4+
"compatibility_date": "2024-12-30",
5+
"compatibility_flags": ["nodejs_compat"],
6+
"r2_buckets": [
7+
{
8+
"binding": "MY_R2",
9+
"bucket_name": "non-existent-r2-bucket",
10+
"remote": true,
11+
},
12+
],
13+
}

0 commit comments

Comments
 (0)