cloudflare / cloudflare/workerd
🐛 Bug Report — Runtime APIs: `KvNamespace#put()` hangs if body not consumed and error response returned
- Dominant language
- C++
- Stars
- 8.7k
- Forks
- 739
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 174
Description
Hey! 👋 With the following `workerd` configuration...
```capnp
using Workerd = import "/workerd/workerd.capnp";
const config :Workerd.Config = (
services = [
( name = "main", worker = .worker ),
( name = "kv", worker = .kvWorker ),
],
sockets = [
( name = "http", address = "*:8080", http = (), service = "main" ),
]
);
const worker :Workerd.Worker = (
compatibilityDate = "2023-08-01",
modules = [ ( name = "index.mjs", esModule = embed "index.mjs" ) ],
bindings = [
( name = "NAMESPACE", kvNamespace = "kv" ),
],
);
const kvWorker :Workerd.Worker = (
compatibilityDate = "2023-08-01",
modules = [ ( name = "kv.mjs", esModule = embed "kv.mjs" ) ],
);
```
```js
// index.mjs
export default {
async fetch(request, env, ctx) {
try {
await env.NAMESPACE.put("key", "value", { expirationTtl: 1 });
return new Response("OK");
} catch (e) {
return new Response("Internal Server Error: " + e.stack, { status: 500 });
}
}
}
```
```js
// kv.mjs
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const expirationTtlHeader = url.searchParams.get("expiration_ttl");
if (expirationTtlHeader !== null) {
const expirationTtl = parseInt(expirationTtlHeader);
if (expirationTtl < 60) {
/* (1) */ await request.arrayBuffer(); // Without this, just hangs
return new Response("Invalid expiration_ttl of 1. Expiration TTL must be at least 60.", {
status: 400,
statusText: "Invalid expiration_ttl of 1. Expiration TTL must be at least 60."
});
}
}
// Pipe the body somewhere
/* (2) */ await request.arrayBuffer(); // Without this, `Error: Network connection lost.`
return new Response();
}
}
```
...removing `/* (1) */`, and passing `{ expirationTtl: 1 }` as above, the request will just hang. I'd expect `Internal Server Error: Error: KV PUT failed: 400 Invalid expiration_ttl of 1. Expiration TTL must be at least 60.` to be returned as the response here.
Removing `/* (2) */` instead and passing a valid `expirationTtl` results in `kj/async-io.c++:631: disconnected: read end of pipe was aborted` logged with `Internal Server Error: Error: Network connection lost.` returned as the response. I'd expect `OK` to be returned as the response here.
Contributor guide
Assessment
This issue has not been assessed yet.