astrid-runtime/astrid · error

MCP gateway principal channel was not initialized

Error message

MCP gateway principal channel was not initialized

What it means

The MCP gateway keeps a per-principal map of active peer channels (`peers`). `peers_for` looks up the channel for a requested principal and throws this error when no entry exists, meaning the attach/session handler asked for a principal whose channel was never registered (or was already removed). It is an internal consistency check: callers are expected to have registered the peer before resolving it.

Source

Thrown at crates/astrid-cli/src/commands/mcp/gateway.rs:197

            |connected| {
                super::require_authenticated_unless_anonymous(
                    &principal,
                    connected.is_authenticated(),
                )
            },
        )
        .await
        .context("failed to recover the persistent daemon uplink")?;
        Ok(())
    }

    async fn peers_for(&self, principal: &str) -> Result<Peers> {
        self.peers
            .lock()
            .await
            .get(principal)
            .cloned()
            .ok_or_else(|| anyhow::anyhow!("MCP gateway principal channel was not initialized"))
    }

    async fn semaphore_for(&self, principal: &str) -> Arc<Semaphore> {
        self.permits
            .lock()
            .await
            .entry(principal.to_owned())
            .or_insert_with(|| Arc::new(Semaphore::new(MAX_ATTACHES)))
            .clone()
    }

    async fn acquire(&self, principal: &str) -> Result<OwnedSemaphorePermit> {
        let semaphore = self.semaphore_for(principal).await;
        if let Ok(permit) = semaphore.clone().try_acquire_owned() {
            return Ok(permit);
        }
        if self.evict_lru_idle().await
            && let Ok(permit) = semaphore.try_acquire_owned()

View on GitHub (pinned to affd8760f4)

Solutions

  1. Check for concurrent `mcp attach` sessions using the same principal; reconnect the evicted session.
  2. Verify the principal identifier used is the exact one registered during attach.
  3. Restart the gateway so peer registration state is rebuilt cleanly.
  4. If reproducible, fix the code path to register the peer before resolving it (move `peers.insert` earlier or keep a strong reference for the session's lifetime).

Example fix

// before
let peer = gateway.peers_for(&principal).await?;
// after
let peer = match gateway.peers_for(&principal).await {
    Ok(p) => p,
    Err(_) => return Err(anyhow::anyhow!("peer {principal} no longer attached; reconnect the MCP session")),
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Go-style pre-check is not exposed; guard at call site
if gateway.peer_keys().await.contains(&principal) { /* proceed */ }

Type guard

fn is_peer_registered(map: &PeersMap, principal: &str) -> bool { map.contains_key(principal) }

Try / catch

match gateway.peers_for(&principal).await {
    Ok(peer) => use(peer),
    Err(e) if e.to_string().contains("not initialized") => reconnect_session(),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling gateway APIs that resolve a peer by principal (e.g. message routing during attach) when the principal's channel was never inserted into the `peers` map, or after it was removed (peer disconnected, idle-evicted, or replaced by a new attach as in `run_attached_session`).

Common situations: A concurrent attach replaced the peer entry and evicted the old session; the gateway restarted between registration and use; a race between peer removal and an in-flight request referencing the principal; passing a wrong/misspelled principal identifier to an internal routing path.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/fbd273670c7c015f. Report an issue: GitHub.