{"record":{"id":"a5050830e1c47473","repo":"xai-org/grok-build","slug":"user-question-session-ended-unexpectedly-coordina","errorCode":null,"errorMessage":"User question session ended unexpectedly (coordinator channel closed)","messagePattern":"User question session ended unexpectedly \\(coordinator channel closed\\)","errorType":"error_code","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-tools/src/implementations/grok_build/ask_user_question/mod.rs","lineNumber":421,"sourceCode":"                    \"missing_resource\",\n                    \"UserQuestionSender\".to_string(),\n                ));\n            }\n        };\n\n        // ── Step 3: Create oneshot ──────────────────────────────────────\n        let (result_tx, result_rx) = tokio::sync::oneshot::channel();\n\n        // ── Step 4: Send UserQuestionRequest ────────────────────────────\n        let request = types::UserQuestionRequest {\n            tool_call_id: ctx.call_id.as_str().to_owned(),\n            questions: input.questions.clone(),\n            result_tx,\n        };\n\n        if sender.0.send(request).is_err() {\n            return Err(xai_tool_runtime::ToolError::execution(\n                xai_tool_protocol::ToolId::new(\"ask_user_question\").expect(\"valid\"),\n                \"User question session ended unexpectedly (coordinator channel closed)\",\n            ));\n        }\n\n        // ── Step 5: Emit UserQuestionAsked + read the wait budget ───────\n        let params = {\n            let questions_json = serde_json::to_value(&input.questions)\n                .unwrap_or_else(|_| serde_json::Value::Array(vec![]));\n            let res = resources.lock().await;\n            if let Some(handle) = res.get::<NotificationHandle>() {\n                handle.0.send_user_question_asked(UserQuestionAsked {\n                    tool_call_id: ctx.call_id.as_str().to_owned(),\n                    questions_json,\n                });\n            }\n            // Shell-injected params win; absent or unset fields keep the legacy\n            // env→default budget so non-shell registry consumers are unchanged.\n            res.get::<crate::types::resources::Params<AskUserQuestionParams>>()","sourceCodeStart":403,"sourceCodeEnd":439,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-tools/src/implementations/grok_build/ask_user_question/mod.rs#L403-L439","documentation":"The `ask_user_question` tool sends the question request to the coordinator over a channel; if `sender.0.send(request)` fails (receiver dropped), the coordinator session is gone, so the tool returns a ToolError with this message rather than panicking. Unlike the others this is a proper Err return, surfaced to the model/tool caller.","triggerScenarios":"The coordinator handling user questions is closed or dropped before/while the tool sends its request — e.g. the interactive session ended, the UI side shut down, or the tool ran outside a live user-question session.","commonSituations":"Running the ask_user_question tool in a non-interactive/headless context where no coordinator exists; session timeout already torn down the coordinator; a prior error crashed the coordinator task; tool invoked after the user closed the prompt UI.","solutions":["Only invoke ask_user_question within an active interactive session with a live coordinator.","Check coordinator lifecycle logs for an earlier panic/exit that dropped the receiver.","Add a readiness check or keep-alive on the coordinator channel before dispatching questions.","Handle the ToolError upstream by skipping the question and continuing with defaults instead of failing the whole turn."],"exampleFix":"// before\nif sender.0.send(request).is_err() {\n    return Err(...\"User question session ended unexpectedly (coordinator channel closed)\"...);\n}\n// after (caller side)\nmatch tool.run(input).await {\n    Err(e) if e.to_string().contains(\"coordinator channel closed\") => proceed_with_defaults(input),\n    other => other,\n}","handlingStrategy":"fallback","validationCode":"// check the coordinator channel is still open before asking\nif sender.0.is_closed() {\n    return proceed_with_defaults(input.questions);\n}","typeGuard":null,"tryCatchPattern":"match sender.0.send(request) {\n    Ok(()) => { /* await response */ }\n    Err(_) => {\n        tracing::warn!(\"coordinator gone; skipping user question\");\n        proceed_with_defaults(input.questions)\n    }\n}","preventionTips":["Invoke ask_user_question only inside live interactive sessions","Monitor coordinator task health; restart it before accepting tool calls","Design tool callers to degrade to defaults when the question channel is closed"],"tags":["rust","channel-closed","tool","interactive-session","acp"],"backgroundTag":"channel-closed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}