aaif-goose/goose · error

Request {} belongs to session {}, not {}

Error message

Request {} belongs to session {}, not {}

What it means

claim_response locks the pending request and compares its stored session_id against the caller-provided one; a mismatch aborts the claim. This prevents session A from answering an elicitation that session B issued — the request id alone is not proof of ownership.

Source

Thrown at crates/goose/src/action_required_manager.rs:129

        let result = self
            .wait_for_response(&id, pending_request, rx, timeout_duration)
            .await;

        self.pending.write().await.remove(&id);

        result
    }

    pub(crate) async fn claim_response(
        &self,
        session_id: &str,
        request_id: &str,
    ) -> Result<PendingResponseClaim> {
        let pending_arc = self.pending_request(request_id).await?;
        let mut pending = pending_arc.lock_owned().await;

        if pending.session_id != session_id {
            return Err(anyhow::anyhow!(
                "Request {} belongs to session {}, not {}",
                request_id,
                pending.session_id,
                session_id
            ));
        }

        let tx = pending
            .response_tx
            .as_ref()
            .ok_or_else(|| anyhow::anyhow!("Request already completed: {}", request_id))?;
        if tx.is_closed() {
            pending.response_tx.take();
            return Err(anyhow::anyhow!("Response channel closed"));
        }

        Ok(PendingResponseClaim {
            request_id: request_id.to_string(),

View on GitHub (pinned to 3810898a74)

Solutions

  1. Route the elicitation response through the same session context that received the request (pass the session id from the incoming message)
  2. Clear pending dialogs when a session is closed or replaced so stale ids cannot be reused
  3. On mismatch, re-request the elicitation in the correct session instead of retrying with the old ids
Defensive patterns

Strategy: validation

Validate before calling

// client-side: derive the session id from the incoming action-required message, never from cached state
let session_id = incoming_action_required.session_id.clone();
let claim = manager.claim_response(&session_id, &request_id).await?;

Try / catch

match manager.claim_response(sid, rid).await {
    Err(e) if e.to_string().contains("belongs to session") => {
        tracing::warn!(%e, "cross-session response blocked; refresh client session state");
        Ok(None) // drop the stale response
    }
    r => r.map(Some),
}

Prevention

When it happens

Trigger: A client holding state for a previous session responds to an elicitation using the old session id after the session was recreated; or a multi-session frontend routes the response to the wrong session's handler.

Common situations: Stale UI state after session switch/reconnect; session ids mixed up in a client that multiplexes several goose sessions.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/241885c3853354a3. Report an issue: GitHub.