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/tail-workers/gotchas.md
1# Tail Workers Gotchas & Debugging23## Critical Pitfalls45### 1. Not Using `ctx.waitUntil()`67**Problem:** Async work doesn't complete or tail Worker times out8**Cause:** Handlers exit immediately; awaiting blocks processing9**Solution:**1011```typescript12// ❌ WRONG - fire and forget13export default {14async tail(events) {15fetch(endpoint, { body: JSON.stringify(events) });16}17};1819// ❌ WRONG - blocking await20export default {21async tail(events, env, ctx) {22await fetch(endpoint, { body: JSON.stringify(events) });23}24};2526// ✅ CORRECT27export default {28async tail(events, env, ctx) {29ctx.waitUntil(30(async () => {31await fetch(endpoint, { body: JSON.stringify(events) });32await processMore();33})()34);35}36};37```3839### 2. Missing `tail()` Handler4041**Problem:** Producer deployment fails42**Cause:** Worker in `tail_consumers` doesn't export `tail()` handler43**Solution:** Ensure `export default { async tail(events, env, ctx) { ... } }`4445### 3. Outcome vs HTTP Status4647**Problem:** Filtering by wrong status48**Cause:** `outcome` is script execution status, not HTTP status4950```typescript51// ❌ WRONG52if (event.outcome === 500) { /* never matches */ }5354// ✅ CORRECT55if (event.outcome === 'exception') { /* script threw */ }56if (event.event?.response?.status === 500) { /* HTTP 500 */ }57```5859### 4. Timestamp Units6061**Problem:** Dates off by 1000x62**Cause:** Timestamps are epoch milliseconds, not seconds6364```typescript65// ❌ WRONG: const date = new Date(event.eventTimestamp * 1000);66// ✅ CORRECT: const date = new Date(event.eventTimestamp);67```6869### 5. Type Name Mismatch7071**Problem:** Using `TailItem` type72**Cause:** Old docs used `TailItem`, SDK uses `TraceItem`7374```typescript75import type { TraceItem } from '@cloudflare/workers-types';76export default {77async tail(events: TraceItem[], env, ctx) { /* ... */ }78};79```8081### 6. Excessive Logging Volume8283**Problem:** Unexpected high costs84**Cause:** Invoked on EVERY producer request85**Solution:** Sample events8687```typescript88export default {89async tail(events, env, ctx) {90if (Math.random() > 0.1) return; // 10% sample91ctx.waitUntil(sendToEndpoint(events));92}93};94```9596### 7. Serialization Issues9798**Problem:** `JSON.stringify()` fails99**Cause:** `log.message` is `unknown[]` with non-serializable values100**Solution:**101102```typescript103const safePayload = events.map(e => ({104...e,105logs: e.logs.map(log => ({106...log,107message: log.message.map(m => {108try { return JSON.parse(JSON.stringify(m)); }109catch { return String(m); }110})111}))112}));113```114115### 8. Missing Error Handling116117**Problem:** Tail Worker silently fails118**Cause:** No try/catch119**Solution:**120121```typescript122ctx.waitUntil((async () => {123try {124await fetch(env.ENDPOINT, { body: JSON.stringify(events) });125} catch (error) {126console.error("Tail error:", error);127await env.FALLBACK_KV.put(`failed:${Date.now()}`, JSON.stringify(events));128}129})());130```131132### 9. Deployment Order133134**Problem:** Producer deployment fails135**Cause:** Tail consumer not deployed yet136**Solution:** Deploy tail consumer FIRST137138```bash139cd tail-worker && wrangler deploy140cd ../producer && wrangler deploy141```142143### 10. No Event Retry144145**Problem:** Events lost when handler fails146**Cause:** Failed invocations NOT retried147**Solution:** Implement fallback storage (see #8)148149## Debugging150151**View logs:** `wrangler tail my-tail-worker`152153**Incremental testing:**1541. Verify receipt: `console.log('Events:', events.length)`1552. Inspect structure: `console.log(JSON.stringify(events[0], null, 2))`1563. Add external call with `ctx.waitUntil()`157158**Monitor dashboard:** Check invocation count (matches producer?), error rate, CPU time159160## Testing161162Add test endpoint to producer:163164```typescript165export default {166async fetch(request) {167if (request.url.includes('/test')) {168console.log('Test log');169throw new Error('Test error');170}171return new Response('OK');172}173};174```175176Trigger: `curl https://producer.example.workers.dev/test`177178## Common Errors179180| Error | Cause | Solution |181|-------|-------|----------|182| "Tail consumer not found" | Not deployed | Deploy tail Worker first |183| "No tail handler" | Missing `tail()` | Add to default export |184| "waitUntil is not a function" | Missing `ctx` | Add `ctx` parameter |185| Timeout | Blocking await | Use `ctx.waitUntil()` |186187## Performance Notes188189- Max 100 events per invocation190- Each consumer receives all events independently191- CPU limits same as regular Workers192- For high volume, use Durable Objects batching193