unicity-aos/aos-ce · warning

aos-mcp: could not retire

Error message

aos-mcp: could not retire {response.host} hook route: {error}

What it means

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.

Solutions

  1. Check the KV backend health and the error text in the log; retry the operation once the store is available.
  2. Verify no concurrent consumer deletes the same token key first; make retirement idempotent.
  3. If the route is genuinely dead, manually remove the stale KV key for that host.
  4. Ignore if the route is short-lived; the warning is non-fatal and the session response was delivered.

Example fix

// before
if retires_session_route(&response)
    && let Err(error) = kv::delete(&token_key)
{
    log::warn(format!("aos-mcp: could not retire {} hook route: {error}", response.host));
}
// after
if retires_session_route(&response)
    && let Err(error) = kv::delete(&token_key)
{
    log::warn(format!("aos-mcp: could not retire {} hook route: {error}", response.host));
    kv::delete(&token_key).ok(); // bounded retry after backoff
}
Defensive patterns

Strategy: fallback

Validate before calling

// before relaying, ensure the KV token key exists and store is reachable
let present = kv::get(&token_key).is_ok();

Type guard

fn route_deletable(key: &str) -> bool { kv::get(key).is_ok() }

Try / catch

match kv::delete(&token_key) {
    Ok(_) => {},
    Err(e) => log::warn("route retire failed, retrying later: {e}"),
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13). Data as JSON: /api/errors/c791f26b45400c20. Report an issue: GitHub.

Appendix: source

Thrown at capsules/capsule-mcp/src/host_hooks.rs:173

    };
    let Ok(token) = std::str::from_utf8(&token) else {
        reject(&response.host, event, "invalid_stored_route");
        return Ok(());
    };
    if derive_route_id(&response.host, &response.session_id, token) != response.route_id {
        reject(&response.host, event, "route_mismatch");
        return Ok(());
    }

    ipc::publish_json(
        &format!("astrid.v1.response.{}", response.delivery_id),
        &response,
    )?;

    if retires_session_route(&response)
        && let Err(error) = kv::delete(&token_key)
    {
        log::warn(format!(
            "aos-mcp: could not retire {} hook route: {error}",
            response.host
        ));
    }
    Ok(())
}

fn authenticate_token(key: &str, request: &HostHookRequest) -> Result<bool, SysError> {
    match kv::get_bytes_opt(key)? {
        Some(expected) => Ok(tokens_match(request.token.as_bytes(), &expected)),
        None if can_register(&request.event) => {
            if kv::cas(key, None, request.token.as_bytes())? {
                Ok(true)
            } else {
                Ok(kv::get_bytes_opt(key)?
                    .as_deref()
                    .is_some_and(|expected| tokens_match(request.token.as_bytes(), expected)))
            }

View on GitHub (pinned to f6f22024fb)