aaif-goose/goose · warning
Request already completed: {}
Error message
Request already completed: {} What it means
PendingResponseClaim::submit moves the response_tx out of the pending request via take(); a second submit on the same claim (or on a request whose tx was already consumed) finds None and fails with this message. It enforces exactly-one-response semantics for action-required elicitations — the guard against double answering.
Source
Thrown at crates/goose/src/action_required_manager.rs:38
}
struct PendingRequest {
session_id: String,
response_tx: Option<tokio::sync::oneshot::Sender<ElicitationOutcome>>,
}
pub(crate) struct PendingResponseClaim {
request_id: String,
pending: OwnedMutexGuard<PendingRequest>,
}
impl PendingResponseClaim {
pub(crate) fn submit(mut self, response: ElicitationOutcome) -> Result<()> {
let tx = self
.pending
.response_tx
.take()
.ok_or_else(|| anyhow::anyhow!("Request already completed: {}", self.request_id))?;
drop(self.pending);
if tx.send(response).is_err() {
return Err(anyhow::anyhow!("Response channel closed"));
}
Ok(())
}
}
pub(crate) struct ActionRequiredManager {
pending: Arc<RwLock<HashMap<String, Arc<Mutex<PendingRequest>>>>>,
action_required_senders: Mutex<HashMap<(String, String), mpsc::Sender<Message>>>,
}
impl ActionRequiredManager {
pub(crate) fn new() -> Self {
Self {View on GitHub (pinned to 3810898a74)
Solutions
- Ensure only one responder owns the claim — consume PendingResponseClaim exactly once per request id
- Deduplicate at the call site: guard with an atomic 'answered' flag or drop the claim after first use
- Treat a second submit as a no-op (catch and ignore 'Request already completed') rather than an error path
Example fix
// before
claim.submit(outcome).await?;
claim.submit(outcome).await?; // duplicate
// after
if let Err(e) = claim.submit(outcome).await {
tracing::debug!(%e, "elicitation already answered");
} Defensive patterns
Strategy: try-catch
Try / catch
if let Err(e) = claim.submit(outcome).await {
if e.to_string().contains("already completed") {
tracing::debug!("duplicate elicitation response ignored");
return Ok(()); // first response stands
}
return Err(e);
} Prevention
- Consume PendingResponseClaim exactly once; move it into the single responder
- Disable UI submit controls after the first response
When it happens
Trigger: Two code paths respond to the same elicitation request id: a UI button handler and a programmatic responder both calling submit; or a retry of a submit that already succeeded.
Common situations: Client code that answers an elicitation and then answers again on timeout/cancel; duplicated event handlers firing for one action; race between an explicit user answer and an automatic timeout responder.
Related errors
- Response channel closed
- Tool call action-required {message}: {tool_call_request_id}
- Elicitation requested but no interactive terminal is availab
- Tool call request not found for elicitation: {}
- Request {} belongs to session {}, not {}
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/c4e765a63c54e6b1.
Report an issue: GitHub.