{"record":{"id":"28118393fb9d6eeb","repo":"aaif-goose/goose","slug":"request-not-found","errorCode":null,"errorMessage":"Request not found: {}","messagePattern":"Request not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/goose/src/action_required_manager.rs","lineNumber":157,"sourceCode":"            .as_ref()\n            .ok_or_else(|| anyhow::anyhow!(\"Request already completed: {}\", request_id))?;\n        if tx.is_closed() {\n            pending.response_tx.take();\n            return Err(anyhow::anyhow!(\"Response channel closed\"));\n        }\n\n        Ok(PendingResponseClaim {\n            request_id: request_id.to_string(),\n            pending,\n        })\n    }\n\n    async fn pending_request(&self, request_id: &str) -> Result<Arc<Mutex<PendingRequest>>> {\n        let pending = self.pending.read().await;\n        pending\n            .get(request_id)\n            .cloned()\n            .ok_or_else(|| anyhow::anyhow!(\"Request not found: {}\", request_id))\n    }\n\n    async fn wait_for_response(\n        &self,\n        request_id: &str,\n        pending_request: Arc<Mutex<PendingRequest>>,\n        mut rx: tokio::sync::oneshot::Receiver<ElicitationOutcome>,\n        timeout_duration: Duration,\n    ) -> Result<ElicitationOutcome> {\n        match timeout(timeout_duration, &mut rx).await {\n            Ok(response) => Self::finish_waiting(request_id, response),\n            Err(_) => {\n                let mut pending = pending_request.lock().await;\n                if pending.response_tx.is_some() {\n                    pending.response_tx.take();\n                    warn!(\"Timeout waiting for response: {}\", request_id);\n                    return Err(anyhow::anyhow!(\"Timeout waiting for user response\"));\n                }","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose/src/action_required_manager.rs#L139-L175","documentation":"Thrown by ActionRequiredManager::pending_request when the request_id is not present in the in-memory pending map. The map is populated by request_and_wait and the entry is removed as soon as the request completes, times out, or fails to enqueue — so an unknown id means the elicitation is no longer answerable (or never existed in this process).","triggerScenarios":"Responding to an elicitation that already completed (entry removed after wait_for_response returns); responding after the waiter timed out and cleaned up (line self.pending.write().await.remove(&id)); using a request_id from a previous process run — the map is per-process and not restored from session history; typo'd or fabricated request_id.","commonSituations":"Double-submitting an elicitation answer (double-click on Accept/Decline in the UI); answering a stale action_required message reloaded from a resumed session after goose restarted; two UI clients answering the same request.","solutions":["Answer the elicitation once, within its lifetime — before it completes or times out","Use the exact request id from the most recent action_required message in the live conversation, not one restored from an old session","If the id is unknown, continue with a normal user message instead of an elicitation response","Guard double-submits in the UI (disable the button after first answer)"],"exampleFix":"// before\nlet claim = manager.claim_response(&session_id, &request_id).await?;\n\n// after\nlet claim = match manager.claim_response(&session_id, &request_id).await {\n    Ok(claim) => claim,\n    Err(e) if e.to_string().contains(\"Request not found\") => {\n        // already answered, expired, or from a previous run — nothing to do\n        return Ok(());\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"try-catch","validationCode":"// Only answer ids that appear as unanswered action_required messages in the\n// live conversation:\nlet is_open = conversation.messages.iter().any(|m| {\n    m.content.iter().any(|c| matches!(c,\n        MessageContent::ActionRequiredElicitation { id, .. } if id == request_id))\n});","typeGuard":"fn request_not_found(e: &anyhow::Error) -> bool {\n    e.to_string().contains(\"Request not found\")\n}","tryCatchPattern":"match manager.claim_response(&session_id, &request_id).await {\n    Ok(claim) => { /* submit */ }\n    Err(e) if request_not_found(&e) => {\n        // already answered, expired, or from a previous process run — no-op\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never reuse elicitation ids from restored/resumed sessions in a new process","Answer each elicitation exactly once","Pass the id verbatim from the received action_required message","Treat 'Request not found' as expected control flow, not a crash"],"tags":["rust","goose","elicitation","stale-state","session"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}