astrid-runtime/astrid · error
MCP attach registration hook_token is invalid
Error message
MCP attach registration hook_token is invalid
What it means
authenticate_registration compares the hook_token in the attach registration against the token stored in GatewayState. A mismatch means the caller does not share the gateway's secret, so the request is rejected even if the principal matches. This complements the principal check as a bearer-token authentication layer.
Solutions
- Re-read the current gateway readiness record and use its hook_token verbatim (no trimming/transforming)
- Confirm you're connecting to the correct gateway socket for your session
- Restart the gateway and use the freshly minted token
- Check the token wasn't truncated or re-encoded during serialization
Example fix
// before
hook_token: old_cached_token,
// after
let ready = read_gateway_ready()?.expect("gateway ready record");
registration.hook_token = ready.hook_token; Defensive patterns
Strategy: validation
Validate before calling
if reg.hook_token != state.hook_token { return Err("stale hook_token — re-read readiness record"); } Try / catch
if let Err(e) = authenticate_registration(®, &state) {
if e.to_string().contains("hook_token is invalid") { refresh_token_and_retry(); }
} Prevention
- Re-read hook_token from the readiness file on every attach, don't cache across restarts
- Compare tokens byte-for-byte without trimming/casing
- Detect gateway restarts (pid change) and refresh credentials
When it happens
Trigger: serve_attach (or tests forged_principal_cannot_select_another_gateway_uplink / missing_hook_token_is_rejected_before_uplink_selection) supplies a hook_token that differs from state.hook_token — e.g. a token from a previous gateway run, another gateway, or a fabricated value.
Common situations: Stale readiness metadata from a previous gateway generation read by the client; two gateways running concurrently and the client mixed up tokens; token rotated on the gateway side but the client cached the old one.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- MCP attach registration principal
- could not authenticate as principal
- guard uplink authenticated as anonymous instead of…
- MCP attach registration is missing hook_token
- MCP gateway control authority is incomplete
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/d488e184c9cc6e5a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-cli/src/commands/mcp/gateway.rs:953
}
validate_workspace(®istration.workspace_abs)?;
Ok(())
}
fn authenticate_registration(
registration: &AttachRegistration,
state: &GatewayState,
) -> Result<astrid_core::PrincipalId> {
let principal = super::lifecycle::resolve_principal(Some(®istration.principal))?;
if principal != state.principal {
anyhow::bail!(
"MCP attach registration principal '{}' is not the authenticated gateway principal '{}'",
principal,
state.principal
);
}
if registration.hook_token != state.hook_token {
anyhow::bail!("MCP attach registration hook_token is invalid");
}
Ok(principal)
}
fn mint_hook_token() -> String {
format!(
"{}{}",
Uuid::new_v4().as_simple(),
Uuid::new_v4().as_simple()
)
}
fn mint_boot_token() -> String {
Uuid::new_v4().as_simple().to_string()
}
fn validate_workspace(value: &str) -> Result<PathBuf> {
if value.is_empty() {View on GitHub (pinned to affd8760f4)