{"record":{"id":"1faa958948f2ac2a","repo":"Hmbown/CodeWhale","slug":"the-cache-route-endpoint-changed-since-the-last-tu","errorCode":null,"errorMessage":"the cache route endpoint changed since the last turn; send a new turn before warming","messagePattern":"the cache route endpoint changed since the last turn; send a new turn before warming","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/tui/src/tui/ui/provider_routes.rs","lineNumber":426,"sourceCode":"        .map_err(anyhow::Error::msg)?;\n    if identity.provider != target.provider || identity.key != target.provider_identity {\n        anyhow::bail!(\n            \"saved cache route identity `{}` now resolves as {}/{} instead of {}/{}; send a new turn before warming\",\n            target.provider_identity,\n            identity.provider.as_str(),\n            identity.key,\n            target.provider.as_str(),\n            target.provider_identity\n        );\n    }\n    let route = resolve_runtime_route_for_identity(config, &identity, Some(&target.model))\n        .map_err(anyhow::Error::msg)?;\n    if let Some(previous_base_url) = target.base_url.as_deref() {\n        let previous_endpoint = crate::route_receipt::endpoint_identity(previous_base_url);\n        let current_endpoint =\n            crate::route_receipt::endpoint_identity(&route.candidate.endpoint().base_url);\n        if previous_endpoint != current_endpoint {\n            anyhow::bail!(\n                \"the cache route endpoint changed since the last turn; send a new turn before warming\"\n            );\n        }\n    }\n    Ok(route)\n}\n\npub(crate) fn error_health_route(\n    app: &App,\n    fallback_provider: ApiProvider,\n) -> (ApiProvider, String) {\n    app.active_turn\n        .as_ref()\n        .and_then(|turn| turn.route.as_ref())\n        .map(|route| (route.provider, route.model.clone()))\n        .or_else(|| {\n            app.pending_turn_route\n                .as_ref()","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/ui/provider_routes.rs#L408-L444","documentation":"resolve_cache_replay_route refuses to warm the KV cache when the selected route's endpoint identity differs from the endpoint used in the previous turn. Warming a cache against a different base URL would be wasted or incorrect work, since the cached prefix belongs to the old endpoint. The error forces a fresh turn to establish the new route before warmup.","triggerScenarios":"Calling run_cache_warmup when target.base_url is set and crate::route_receipt::endpoint_identity(previous_base_url) != endpoint_identity(route.candidate.endpoint().base_url) — i.e. the auto route provider/base URL changed since the last recorded turn.","commonSituations":"The user switched model providers or base URL between turns (config change, route failover, registry update) and then triggered a cache warmup before sending a new turn.","solutions":["Send a new turn through the normal request path so a route receipt for the current endpoint is recorded, then retry the warmup.","If the endpoint change is unintended, revert the model/provider/base URL configuration back to the previous endpoint and retry.","Clear or update the stored route receipt (target.base_url) so it matches the current route's endpoint."],"exampleFix":"// before: warm immediately after changing providers\nrun_cache_warmup(...).await?;\n\n// after: only warm when the endpoint is unchanged, otherwise send a turn first\nif endpoint_identity(&target.base_url) == endpoint_identity(&route.candidate.endpoint().base_url) {\n    run_cache_warmup(...).await?;\n} else {\n    // send a normal turn to re-record the route, then warm\n}","handlingStrategy":"validation","validationCode":"let prev = crate::route_receipt::endpoint_identity(target.base_url?);\nlet cur = crate::route_receipt::endpoint_identity(route.candidate.endpoint().base_url);\nif prev != cur { /* send a turn first, skip warmup */ }","typeGuard":null,"tryCatchPattern":"match resolve_cache_replay_route(...) {\n    Ok(route) => warm(route),\n    Err(e) if e.to_string().contains(\"endpoint changed\") => send_new_turn_then_retry(),\n    Err(e) => return Err(e),\n}","preventionTips":["Only run cache warmup immediately after a successful turn on the same route.","Compare endpoint identity before every warmup call.","Treat provider/base URL switches as invalidating all pending warmups."],"tags":["cache","routing","kv-cache","route-mismatch"],"backgroundTag":"invalid-state-transition","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}