Files
claude-skills/cloudflare/references/agents-sdk/gotchas.md
2026-01-30 03:04:10 +00:00

5.0 KiB

Gotchas & Best Practices

Common Errors

"setState() not syncing"

Cause: Mutating state directly or not calling setState() after modifications
Solution: Always use setState() with immutable updates:

// ❌ this.state.count++
// ✅ this.setState({...this.state, count: this.state.count + 1})

"Message history grows unbounded (AIChatAgent)"

Cause: this.messages in AIChatAgent accumulates all messages indefinitely
Solution: Manually trim old messages periodically:

export class ChatAgent extends AIChatAgent<Env> {
  async onChatMessage(onFinish) {
    // Keep only last 50 messages
    if (this.messages.length > 50) {
      this.messages = this.messages.slice(-50);
    }
    
    return this.streamText({ model: openai("gpt-4"), messages: this.messages, onFinish });
  }
}

"SQL injection vulnerability"

Cause: Direct string interpolation in SQL queries Solution: Use parameterized queries:

// ❌ this.sql`...WHERE id = '${userId}'`
// ✅ this.sql`...WHERE id = ${userId}`

"WebSocket connection timeout"

Cause: Not calling conn.accept() in onConnect Solution: Always accept connections:

async onConnect(conn: Connection, ctx: ConnectionContext) { conn.accept(); conn.setState({userId: "123"}); }

"Schedule limit exceeded"

Cause: More than 1000 scheduled tasks per agent Solution: Clean up old schedules and limit creation rate:

async checkSchedules() { if ((await this.getSchedules()).length > 800) console.warn("Near limit!"); }

"AI Gateway unavailable"

Cause: AI service timeout or quota exceeded
Solution: Add error handling and fallbacks:

try { 
  return await this.env.AI.run(model, {prompt}); 
} catch (e) { 
  console.error("AI error:", e);
  return {error: "Unavailable"}; 
}

"@callable method returns undefined"

Cause: Method doesn't return JSON-serializable value, or has non-serializable types
Solution: Ensure return values are plain objects/arrays/primitives:

// ❌ Returns class instance
@callable()
async getData() { return new Date(); }

// ✅ Returns serializable object
@callable()
async getData() { return { timestamp: Date.now() }; }

"Resumable stream not resuming"

Cause: Stream ID must be deterministic for resumption to work
Solution: Use AIChatAgent (automatic) or ensure consistent stream IDs:

// AIChatAgent handles this automatically
export class ChatAgent extends AIChatAgent<Env> {
  // Resumption works out of the box
}

"MCP connection loss on hibernation"

Cause: MCP server connections don't survive hibernation
Solution: Re-register servers in onStart() or check connection status:

onStart() {
  // Re-register MCP servers after hibernation
  await this.mcp.registerServer("github", { url: env.MCP_URL, auth: {...} });
}

"Agent not found"

Cause: Durable Object binding missing or incorrect class name
Solution: Verify DO binding in wrangler.jsonc and class name matches

Rate Limits & Quotas

Resource/Limit Value Notes
CPU per request 30s (std), 300s (max) Set in wrangler.jsonc
Memory per instance 128MB Shared with WebSockets
Storage per agent 10GB SQLite storage
Scheduled tasks 1000 per agent Monitor with getSchedules()
WebSocket connections Unlimited Within memory limits
SQL columns 100 Per table
SQL row size 2MB Key + value
WebSocket message 32MiB Max size
DO requests/sec ~1000 Per unique DO instance; rate limit if needed
AI Gateway (Workers AI) Model-specific Check dashboard for limits
MCP requests Depends on server Implement retry/backoff

Best Practices

State Management

  • Use immutable updates: setState({...this.state, key: newValue})
  • Trim unbounded arrays (messages, logs) periodically
  • Store large data in SQL, not state

SQL Usage

  • Create tables in onStart(), not onRequest()
  • Use parameterized queries: sql`WHERE id = ${id}` (NOT sql`WHERE id = '${id}'`)
  • Index frequently queried columns

Scheduling

  • Monitor schedule count: await this.getSchedules()
  • Cancel completed tasks to stay under 1000 limit
  • Use cron strings for recurring tasks

WebSockets

  • Always call conn.accept() in onConnect()
  • Handle client disconnects gracefully
  • Broadcast to this.connections efficiently

AI Integration

  • Use AIChatAgent for chat interfaces (auto-streaming, resumption)
  • Trim message history to avoid token limits
  • Handle AI errors with try/catch and fallbacks

Production Deployment

  • Rate limiting: Implement request throttling for high-traffic agents (>1000 req/s)
  • Monitoring: Log critical errors, track schedule count, monitor storage usage
  • Graceful degradation: Handle AI service outages with fallbacks
  • Message trimming: Enforce max history length (e.g., 100 messages) in AIChatAgent
  • MCP reliability: Re-register servers on hibernation, implement retry logic