# Workers Gotchas

## Common Errors

### "Too much CPU time used"

**Cause:** Worker exceeded CPU time limit (10ms standard, 30ms unbound)  
**Solution:** Use `ctx.waitUntil()` for background work, offload heavy compute to Durable Objects, or consider Workers AI for ML workloads

### "Module-Level State Lost"

**Cause:** Workers are stateless between requests; module-level variables reset unpredictably  
**Solution:** Use KV, D1, or Durable Objects for persistent state; don't rely on module-level variables

### "Body has already been used"

**Cause:** Attempting to read response body twice (bodies are streams)  
**Solution:** Clone response before reading: `response.clone()` or read once and create new Response with the text

### "Node.js module not found"

**Cause:** Node.js built-ins not available by default  
**Solution:** Use Workers APIs (e.g., R2 for file storage) or enable Node.js compat with `"compatibility_flags": ["nodejs_compat_v2"]`

### "Cannot fetch in global scope"

**Cause:** Attempting to use fetch during module initialization  
**Solution:** Move fetch calls inside handler functions (fetch, scheduled, etc.) where they're allowed

### "Subrequest depth limit exceeded"

**Cause:** Too many nested subrequests creating deep call chain  
**Solution:** Flatten request chain or use service bindings for direct Worker-to-Worker communication

### "D1 read-after-write inconsistency"

**Cause:** D1 is eventually consistent; reads may not reflect recent writes  
**Solution:** Use D1 Sessions (2024+) to guarantee read-after-write consistency within a session:

```typescript
const session = env.DB.withSession()
await session.prepare('INSERT INTO users (name) VALUES (?)').bind('Alice').run()
const user = await session.prepare('SELECT * FROM users WHERE name = ?').bind('Alice').first() // Guaranteed to see Alice
```

**When to use sessions:** Write → Read patterns, transactions requiring consistency

### "wrangler types not generating TypeScript definitions"

**Cause:** Type generation not configured or outdated  
**Solution:** Run `npx wrangler types` after changing bindings in wrangler.jsonc:

```bash
npx wrangler types  # Generates .wrangler/types/runtime.d.ts
```

Add to `tsconfig.json`: `"include": [".wrangler/types/**/*.ts"]`

Then import: `import type { Env } from './.wrangler/types/runtime';`

### "Durable Object RPC errors with deprecated fetch pattern"

**Cause:** Using old `stub.fetch()` pattern instead of RPC (2024+)  
**Solution:** Export methods directly, call via RPC:

```typescript
// ❌ Old fetch pattern
export class MyDO {
  async fetch(request: Request) {
    const { method } = await request.json()
    if (method === 'increment') return new Response(String(await this.increment()))
  }
  async increment() {
    return ++this.value
  }
}
const stub = env.DO.get(id)
const res = await stub.fetch('http://x', {
  method: 'POST',
  body: JSON.stringify({ method: 'increment' }),
})

// ✅ RPC pattern (type-safe, no serialization overhead)
export class MyDO {
  async increment() {
    return ++this.value
  }
}
const stub = env.DO.get(id)
const count = await stub.increment() // Direct method call
```

### "WebSocket connection closes unexpectedly"

**Cause:** Worker reaches CPU limit while maintaining WebSocket connection  
**Solution:** Use WebSocket hibernation (2024+) to offload idle connections:

```typescript
export class WebSocketDO {
  async webSocketMessage(ws: WebSocket, message: string) {
    // Handle message
  }
  async webSocketClose(ws: WebSocket, code: number) {
    // Cleanup
  }
}
```

Hibernation automatically suspends inactive connections, wakes on events

### "Framework middleware not working with Workers"

**Cause:** Framework expects Node.js primitives (e.g., Express uses Node streams)  
**Solution:** Use Workers-native frameworks (Hono, itty-router, Worktop) or adapt middleware:

```typescript
// ✅ Hono (Workers-native)
import { Hono } from 'hono'
const app = new Hono()
app.use('*', async (c, next) => {
  /* middleware */ await next()
})
```

See [frameworks.md](./frameworks.md) for full patterns

## Limits

| Limit               | Value     | Notes                         |
| ------------------- | --------- | ----------------------------- |
| Request size        | 100 MB    | Maximum incoming request size |
| Response size       | Unlimited | Supports streaming            |
| CPU time (standard) | 10ms      | Standard Workers              |
| CPU time (unbound)  | 30ms      | Unbound Workers               |
| Subrequests         | 10,000    | Per request                   |
| KV reads            | 1000      | Per request                   |
| KV write size       | 25 MB     | Maximum per write             |
| Environment size    | 5 MB      | Total size of env bindings    |

## See Also

- [Patterns](./patterns.md) - Best practices
- [API](./api.md) - Runtime APIs
- [Configuration](./configuration.md) - Setup
- [Frameworks](./frameworks.md) - Hono, routing, validation
