All skills
Skillintermediate

Binding Gotchas and Troubleshooting

```typescript // ❌ DANGEROUS - env cached at deploy time const apiKey = env.API_KEY; // ERROR: env not available in global scope

Claude Code Knowledge Pack7/10/2026

Overview

Binding Gotchas and Troubleshooting

Critical: Global Scope Mutation

❌ THE #1 GOTCHA: Caching env in Global Scope

// ❌ DANGEROUS - env cached at deploy time
const apiKey = env.API_KEY;  // ERROR: env not available in global scope

  async fetch(request: Request, env: Env) {
    // Uses undefined or stale value!
  }
}

Why it breaks:

  • env not available in global scope
  • If using workarounds, secrets may not update without redeployment
  • Leads to "Cannot read property 'X' of undefined" errors

✅ Always access env per-request:


  async fetch(request: Request, env: Env) {
    const apiKey = env.API_KEY;  // Fresh every request
  }
}

Common Errors

"env.MY_KV is undefined"

Cause: Name mismatch or not configured
Solution: Check wrangler.jsonc (case-sensitive), run npx wrangler types, verify npx wrangler kv namespace list

"Property 'MY_KV' does not exist on type 'Env'"

Cause: Types not generated
Solution: npx wrangler types

"preview_id is required for --remote"

Cause: Missing preview binding
Solution: Add "preview_id": "dev-id" or use npx wrangler dev (local mode)

"Secret updated but Worker still uses old value"

Cause: Cached in global scope or not redeployed
Solution: Avoid global caching, redeploy after secret change

"KV get() returns null for existing key"

Cause: Eventual consistency (60s), wrong namespace, wrong environment
Solution:

# Check key exists
npx wrangler kv key get --binding=MY_KV "your-key"

# Verify namespace ID
npx wrangler kv namespace list

# Check environment
npx wrangler deployments list

"D1 database not found"

Solution: npx wrangler d1 list, verify ID in wrangler.jsonc

"Service binding returns 'No such service'"

Cause: Target Worker not deployed, name mismatch, environment mismatch
Solution:

# List deployed Workers
npx wrangler deployments list --name=target-worker

# Check service binding config
cat wrangler.jsonc | grep -A2 services

# Deploy target first
cd ../target-worker && npx wrangler deploy

"Rate limit exceeded" on KV writes

Cause: >1 write/second per key
Solution: Use different keys, Durable Objects, or Queues

Type Safety Gotchas

Missing @cloudflare/workers-types

Error: Cannot find name 'Request'
Solution: npm install -D @cloudflare/workers-types, add to tsconfig.json "types"

Binding Type Mismatches

// ❌ Wrong - KV returns string | null
const value: string = await env.MY_KV.get('key');

// ✅ Handle null
const value = await env.MY_KV.get('key');
if (!value) return new Response('Not found', { status: 404 });

Environment Gotchas

Wrong Environment Deployed

Solution: Check npx wrangler deployments list, use --env flag

Secrets Not Per-Environment

Solution: Set per environment: npx wrangler secret put API_KEY --env staging

Development Gotchas

wrangler dev vs deploy:

  • dev: Uses preview_id or local bindings, secrets not available
  • deploy: Uses production id, secrets available

Access secrets in dev: npx wrangler dev --remote
Persist local data: npx wrangler dev --persist

Performance Gotchas

Sequential Binding Calls

// ❌ Slow
const user = await env.DB.prepare('...').first();
const config = await env.MY_KV.get('config');

// ✅ Parallel
const [user, config] = await Promise.all([
  env.DB.prepare('...').first(),
  env.MY_KV.get('config')
]);

Security Gotchas

❌ Secrets in logs: console.log('Key:', env.API_KEY) - visible in dashboard
console.log('Key:', env.API_KEY ? '***' : 'missing')

❌ Exposing env: return Response.json(env) - exposes all bindings
Never return env object in responses

Limits Reference

ResourceLimitImpactPlan
Bindings per Worker64 totalAll binding types combinedAll
Environment variables64 max, 5KB eachPer WorkerAll
Secret size1KBPer secretAll
KV key size512 bytesUTF-8 encodedAll
KV value size25 MBPer valueAll
KV writes per key1/secondPer key; exceeding = 429 errorAll
KV list() results1000 keysPer call; use cursor for moreAll
KV operations1000 reads/dayFree tier onlyFree
R2 object size5 TBPer objectAll
R2 operations1M Class A/month freeWritesAll
D1 database size10 GBPer databaseAll
D1 rows per query100,000Result set limitAll
D1 databases10Free tierFree
Queue batch size100 messagesPer consumer batchAll
Queue message size128 KBPer messageAll
Service binding callsUnlimitedCounts toward CPU timeAll
Durable Objects1M requests/month freeFirst 1MFree

Debugging Tips

# Check configuration
npx wrangler deploy --dry-run       # Validate config without deploying
npx wrangler kv namespace list      # List KV namespaces
npx wrangler secret list            # List secrets (not values)
npx wrangler deployments list       # Recent deployments

# Inspect bindings
npx wrangler kv key list --binding=MY_KV
npx wrangler kv key get --binding=MY_KV "key-name"
npx wrangler r2 object get my-bucket/file.txt
npx wrangler d1 execute my-db --command="SELECT * FROM sqlite_master"

# Test locally
npx wrangler dev                  # Local mode
npx wrangler dev --remote         # Production bindings
npx wrangler dev --persist        # Persist data across restarts

# Verify types
npx wrangler types
cat .wrangler/types/runtime.d.ts | grep "interface Env"

# Debug specific binding issues
npx wrangler tail                 # Stream logs in real-time
npx wrangler tail --format=pretty # Formatted logs

See Also