# Smart Placement Gotchas ## Common Errors ### "INSUFFICIENT_INVOCATIONS" **Cause:** Not enough traffic for Smart Placement to analyze **Solution:** - Ensure Worker receives consistent global traffic - Wait longer (analysis takes up to 15 minutes) - Send test traffic from multiple global locations - Check Worker has fetch event handler ### "UNSUPPORTED_APPLICATION" **Cause:** Smart Placement made Worker slower rather than faster **Reasons:** - Worker doesn't make backend calls (runs faster at edge) - Backend calls are cached (network latency to user more important) - Backend service has good global distribution - Worker serves static assets or Pages content **Solutions:** - Disable Smart Placement: `{ "placement": { "mode": "off" } }` - Review whether Worker actually benefits from Smart Placement - Consider caching strategy to reduce backend calls - For Pages/Assets Workers, use separate backend Worker with Smart Placement ### "No request duration metrics" **Cause:** Smart Placement not enabled, insufficient time passed, insufficient traffic, or analysis incomplete **Solution:** - Ensure Smart Placement enabled in config - Wait 15+ minutes after deployment - Verify Worker has sufficient traffic - Check `placement_status` is `SUCCESS` ### "cf-placement header missing" **Cause:** Smart Placement not enabled, beta feature removed, or Worker not analyzed yet **Solution:** Verify Smart Placement enabled, wait for analysis (15min), check if beta feature still available ## Pages/Assets + Smart Placement Performance Degradation **Problem:** Static assets load 2-5x slower when Smart Placement enabled with `run_worker_first = true`. **Cause:** Smart Placement routes ALL requests (including static assets like HTML, CSS, JS, images) to remote locations. Static content should ALWAYS be served from edge closest to user. **Solution:** Split into separate Workers OR disable Smart Placement: ```jsonc // ❌ BAD - Assets routed away from user { "name": "pages-app", "placement": { "mode": "smart" }, "assets": { "run_worker_first": true } } // ✅ GOOD - Assets at edge, API optimized // frontend/wrangler.jsonc { "name": "frontend", "assets": { "run_worker_first": true } // No placement field - stays at edge } // backend/wrangler.jsonc { "name": "backend-api", "placement": { "mode": "smart" } } ``` This is one of the most common and impactful Smart Placement misconfigurations. ## Monolithic Full-Stack Worker **Problem:** Frontend and backend logic in single Worker with Smart Placement enabled. **Cause:** Smart Placement optimizes for backend latency but increases user-facing response time. **Solution:** Split into two Workers: ```jsonc // frontend/wrangler.jsonc { "name": "frontend", "placement": { "mode": "off" }, // Explicit: stay at edge "services": [{ "binding": "BACKEND", "service": "backend-api" }] } // backend/wrangler.jsonc { "name": "backend-api", "placement": { "mode": "smart" }, "d1_databases": [{ "binding": "DB", "database_id": "xxx" }] } ``` ## Local Development Confusion **Issue:** Smart Placement doesn't work in `wrangler dev`. **Explanation:** Smart Placement only activates in production deployments, not local development. **Solution:** Test Smart Placement in staging environment: `wrangler deploy --env staging` ## Baseline Traffic & Analysis Time **Note:** Smart Placement routes 1% of requests WITHOUT optimization for comparison (expected). **Analysis time:** Up to 15 minutes. During analysis, Worker runs at edge. Monitor `placement_status`. ## RPC Methods Not Affected (Critical Limitation) **Problem:** Enabled Smart Placement on backend but RPC calls still slow. **Cause:** Smart Placement ONLY affects `fetch` handlers. RPC methods (Service Bindings with `WorkerEntrypoint`) are NEVER affected. **Why:** RPC bypasses `fetch` handler - Smart Placement can only route `fetch` requests. **Solution:** Convert to fetch-based Service Bindings: ```typescript // ❌ RPC - Smart Placement has NO EFFECT export class BackendRPC extends WorkerEntrypoint { async getData() { // ALWAYS runs at edge return await this.env.DATABASE.prepare('SELECT * FROM table').all(); } } // ✅ Fetch - Smart Placement WORKS export default { async fetch(request: Request, env: Env): Promise { // Runs close to DATABASE when Smart Placement enabled const data = await env.DATABASE.prepare('SELECT * FROM table').all(); return Response.json(data); } } ``` ## Requirements - **Wrangler 2.20.0+** required - **Consistent multi-region traffic** needed for analysis - **Only affects fetch handlers** - RPC methods and named entrypoints not affected ## Limits | Resource/Limit | Value | Notes | |----------------|-------|-------| | Analysis time | Up to 15 minutes | After enabling | | Baseline traffic | 1% | Routed without optimization | | Min Wrangler version | 2.20.0+ | Required | | Traffic requirement | Multi-region | Consistent needed | ## Disabling Smart Placement ```jsonc { "placement": { "mode": "off" } } // Explicit disable // OR remove "placement" field entirely (same effect) ``` Both behaviors identical - Worker runs at edge closest to user. ## When NOT to Use Smart Placement - Workers serving only static content or cached responses - Workers without significant backend communication - Pure edge logic (auth checks, redirects, simple transformations) - Workers without fetch event handlers - Pages/Assets Workers with `run_worker_first = true` - Workers using RPC methods instead of fetch handlers These scenarios won't benefit and may perform worse with Smart Placement.