Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/agents-sdk/gotchas.md
1# Gotchas & Best Practices23## Common Errors45### "setState() not syncing"67**Cause:** Mutating state directly or not calling `setState()` after modifications8**Solution:** Always use `setState()` with immutable updates:9```ts10// ❌ this.state.count++11// ✅ this.setState({...this.state, count: this.state.count + 1})12```1314### "Message history grows unbounded (AIChatAgent)"1516**Cause:** `this.messages` in `AIChatAgent` accumulates all messages indefinitely17**Solution:** Manually trim old messages periodically:18```ts19export class ChatAgent extends AIChatAgent<Env> {20async onChatMessage(onFinish) {21// Keep only last 50 messages22if (this.messages.length > 50) {23this.messages = this.messages.slice(-50);24}2526return this.streamText({ model: openai("gpt-4"), messages: this.messages, onFinish });27}28}29```3031### "SQL injection vulnerability"3233**Cause:** Direct string interpolation in SQL queries34**Solution:** Use parameterized queries:35```ts36// ❌ this.sql`...WHERE id = '${userId}'`37// ✅ this.sql`...WHERE id = ${userId}`38```3940### "WebSocket connection timeout"4142**Cause:** Not calling `conn.accept()` in `onConnect`43**Solution:** Always accept connections:44```ts45async onConnect(conn: Connection, ctx: ConnectionContext) { conn.accept(); conn.setState({userId: "123"}); }46```4748### "Schedule limit exceeded"4950**Cause:** More than 1000 scheduled tasks per agent51**Solution:** Clean up old schedules and limit creation rate:52```ts53async checkSchedules() { if ((await this.getSchedules()).length > 800) console.warn("Near limit!"); }54```5556### "AI Gateway unavailable"5758**Cause:** AI service timeout or quota exceeded59**Solution:** Add error handling and fallbacks:60```ts61try {62return await this.env.AI.run(model, {prompt});63} catch (e) {64console.error("AI error:", e);65return {error: "Unavailable"};66}67```6869### "@callable method returns undefined"7071**Cause:** Method doesn't return JSON-serializable value, or has non-serializable types72**Solution:** Ensure return values are plain objects/arrays/primitives:73```ts74// ❌ Returns class instance75@callable()76async getData() { return new Date(); }7778// ✅ Returns serializable object79@callable()80async getData() { return { timestamp: Date.now() }; }81```8283### "Resumable stream not resuming"8485**Cause:** Stream ID must be deterministic for resumption to work86**Solution:** Use AIChatAgent (automatic) or ensure consistent stream IDs:87```ts88// AIChatAgent handles this automatically89export class ChatAgent extends AIChatAgent<Env> {90// Resumption works out of the box91}92```9394### "MCP connection loss on hibernation"9596**Cause:** MCP server connections don't survive hibernation97**Solution:** Re-register servers in `onStart()` or check connection status:98```ts99onStart() {100// Re-register MCP servers after hibernation101await this.mcp.registerServer("github", { url: env.MCP_URL, auth: {...} });102}103```104105### "Agent not found"106107**Cause:** Durable Object binding missing or incorrect class name108**Solution:** Verify DO binding in wrangler.jsonc and class name matches109110## Rate Limits & Quotas111112| Resource/Limit | Value | Notes |113|----------------|-------|-------|114| CPU per request | 30s (std), 300s (max) | Set in wrangler.jsonc |115| Memory per instance | 128MB | Shared with WebSockets |116| Storage per agent | 10GB | SQLite storage |117| Scheduled tasks | 1000 per agent | Monitor with `getSchedules()` |118| WebSocket connections | Unlimited | Within memory limits |119| SQL columns | 100 | Per table |120| SQL row size | 2MB | Key + value |121| WebSocket message | 32MiB | Max size |122| DO requests/sec | ~1000 | Per unique DO instance; rate limit if needed |123| AI Gateway (Workers AI) | Model-specific | Check dashboard for limits |124| MCP requests | Depends on server | Implement retry/backoff |125126## Best Practices127128### State Management129- Use immutable updates: `setState({...this.state, key: newValue})`130- Trim unbounded arrays (messages, logs) periodically131- Store large data in SQL, not state132133### SQL Usage134- Create tables in `onStart()`, not `onRequest()`135- Use parameterized queries: `` sql`WHERE id = ${id}` `` (NOT `` sql`WHERE id = '${id}'` ``)136- Index frequently queried columns137138### Scheduling139- Monitor schedule count: `await this.getSchedules()`140- Cancel completed tasks to stay under 1000 limit141- Use cron strings for recurring tasks142143### WebSockets144- Always call `conn.accept()` in `onConnect()`145- Handle client disconnects gracefully146- Broadcast to `this.connections` efficiently147148### AI Integration149- Use `AIChatAgent` for chat interfaces (auto-streaming, resumption)150- Trim message history to avoid token limits151- Handle AI errors with try/catch and fallbacks152153### Production Deployment154- **Rate limiting:** Implement request throttling for high-traffic agents (>1000 req/s)155- **Monitoring:** Log critical errors, track schedule count, monitor storage usage156- **Graceful degradation:** Handle AI service outages with fallbacks157- **Message trimming:** Enforce max history length (e.g., 100 messages) in AIChatAgent158- **MCP reliability:** Re-register servers on hibernation, implement retry logic159