{"record":{"id":"c791f26b45400c20","repo":"unicity-aos/aos-ce","slug":"aos-mcp-could-not-retire-response-host-hook-route-error","errorCode":null,"errorMessage":"aos-mcp: could not retire {response.host} hook route: {error}","messagePattern":"aos-mcp: could not retire (.+?) hook route: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"capsules/capsule-mcp/src/host_hooks.rs","lineNumber":173,"sourceCode":"    };\n    let Ok(token) = std::str::from_utf8(&token) else {\n        reject(&response.host, event, \"invalid_stored_route\");\n        return Ok(());\n    };\n    if derive_route_id(&response.host, &response.session_id, token) != response.route_id {\n        reject(&response.host, event, \"route_mismatch\");\n        return Ok(());\n    }\n\n    ipc::publish_json(\n        &format!(\"astrid.v1.response.{}\", response.delivery_id),\n        &response,\n    )?;\n\n    if retires_session_route(&response)\n        && let Err(error) = kv::delete(&token_key)\n    {\n        log::warn(format!(\n            \"aos-mcp: could not retire {} hook route: {error}\",\n            response.host\n        ));\n    }\n    Ok(())\n}\n\nfn authenticate_token(key: &str, request: &HostHookRequest) -> Result<bool, SysError> {\n    match kv::get_bytes_opt(key)? {\n        Some(expected) => Ok(tokens_match(request.token.as_bytes(), &expected)),\n        None if can_register(&request.event) => {\n            if kv::cas(key, None, request.token.as_bytes())? {\n                Ok(true)\n            } else {\n                Ok(kv::get_bytes_opt(key)?\n                    .as_deref()\n                    .is_some_and(|expected| tokens_match(request.token.as_bytes(), expected)))\n            }","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/capsules/capsule-mcp/src/host_hooks.rs#L155-L191","documentation":"In capsule-mcp's host hook relay, after relaying a response whose shape indicates the session's hook route is finished, the code deletes the route's KV entry (kv::delete(&token_key)). If that delete fails, the stale route is left registered and this warning is logged; the response itself was still delivered successfully. This is a cleanup-failure warning, not a relay failure.","triggerScenarios":"kv::delete(&token_key) returns Err during relay_response when retires_session_route(&response) is true — i.e., the KV store rejected or failed the delete of the hook-route token for response.host (KV backend unavailable, key already gone via a different code path, storage error).","commonSituations":"KV store restart or transient storage errors during session teardown; concurrent sessions deleting the same route; host misconfiguration causing token_key collisions or stale keys.","solutions":["Check the KV backend health and the error text in the log; retry the operation once the store is available.","Verify no concurrent consumer deletes the same token key first; make retirement idempotent.","If the route is genuinely dead, manually remove the stale KV key for that host.","Ignore if the route is short-lived; the warning is non-fatal and the session response was delivered."],"exampleFix":"// before\nif retires_session_route(&response)\n    && let Err(error) = kv::delete(&token_key)\n{\n    log::warn(format!(\"aos-mcp: could not retire {} hook route: {error}\", response.host));\n}\n// after\nif retires_session_route(&response)\n    && let Err(error) = kv::delete(&token_key)\n{\n    log::warn(format!(\"aos-mcp: could not retire {} hook route: {error}\", response.host));\n    kv::delete(&token_key).ok(); // bounded retry after backoff\n}","handlingStrategy":"fallback","validationCode":"// before relaying, ensure the KV token key exists and store is reachable\nlet present = kv::get(&token_key).is_ok();","typeGuard":"fn route_deletable(key: &str) -> bool { kv::get(key).is_ok() }","tryCatchPattern":"match kv::delete(&token_key) {\n    Ok(_) => {},\n    Err(e) => log::warn(\"route retire failed, retrying later: {e}\"),\n}","preventionTips":["Monitor KV backend health before session teardown","Make route retirement idempotent","Alert on repeated retire warnings per host"],"tags":["kv","cleanup","session-teardown","logging"],"backgroundTag":"database-write-failed","analyzedSha":"f6f22024fb1e8d122f28a1b4a9f75aee448ae839","analyzedAt":"2026-09-13T03:04:44.565Z","contentChangedAt":"2026-09-13T03:04:44.565Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}