Skip to content

Commit e7b634b

Browse files
authored
docs(cloudflare): troubleshoot DB client error (#131)
1 parent 93b65f2 commit e7b634b

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

pages/cloudflare/troubleshooting.mdx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,49 @@ You may want to modify how Wrangler resolves multiple exports, such that when yo
4040
WRANGLER_BUILD_CONDITIONS=""
4141
WRANGLER_BUILD_PLATFORM="node"
4242
```
43+
44+
### `Error: Cannot perform I/O on behalf of a different request.`
45+
46+
Some DB clients (i.e. [`postgres`](https://www.npmjs.com/package/postgres)) create a connection to the DB server when they are first instantiated and re-use it for later requests.
47+
This programming model is not compatible with the Workers runtime where a connection can not be re-used in a different request.
48+
49+
The following error is generated in such a case:
50+
51+
```text
52+
⨯ Error: Cannot perform I/O on behalf of a different request. I/O objects (such as streams, request/response bodies, and others) created in the context of one request handler cannot be accessed from a different request's handler. This is a limitation of Cloudflare Workers which allows us to improve overall performance. (I/O type: Writable)
53+
```
54+
55+
To solve this, you should create the DB client inside a request context and not keep a global DB client.
56+
57+
A global client would not work:
58+
59+
```ts
60+
// src/lib/db.ts
61+
import postgres from "postgres";
62+
63+
// `client` is global.
64+
// As the connection would be shared across requests, it fails on worker
65+
export const client = postgres(process.env.DATABASE_URL, { max: 5 });
66+
67+
// src/app/api/route.ts
68+
import { client } from "@/db/db";
69+
70+
export const dynamic = "force-dynamic";
71+
72+
export async function GET() {
73+
return new Response(JSON.stringify(await client`SELECT * FROM users;`));
74+
}
75+
```
76+
77+
It can fixed by creating the client for each incoming request:
78+
79+
```ts
80+
// src/app/api/route.ts
81+
export const dynamic = "force-dynamic";
82+
83+
export async function GET() {
84+
// The client is created for each incoming request and no connection is shared across requests
85+
const client = postgres(process.env.DATABASE_URL, { max: 5 });
86+
return new Response(JSON.stringify(await client`SELECT * FROM users;`));
87+
}
88+
```

0 commit comments

Comments
 (0)