Hmbown/CodeWhale · error · anyhow::Error
thread '{thread_id}' not found
Error message
thread '{thread_id}' not found What it means
submit_user_input could not find thread_id in the active engines map. The user-input protocol only works against a thread whose engine is currently started (an active turn exists to receive the answer), so a thread that was never started, has finished, or was evicted fails here.
Source
Thrown at crates/tui/src/runtime_threads.rs:3274
}
};
let ack =
self.spawn_dynamic_tool_settlement(claim, DynamicToolTerminalOutcome::Resolved(result));
Ok(Self::await_dynamic_tool_settlement(ack)
.await?
.result_accepted)
}
pub async fn submit_user_input(
&self,
thread_id: &str,
input_id: &str,
response: crate::tools::user_input::UserInputResponse,
) -> Result<bool> {
let engine = {
let active = self.active.lock().await;
let Some(state) = active.engines.get(thread_id) else {
bail!("thread '{thread_id}' not found");
};
state.engine.clone()
};
let request = match self.claim_pending_user_input(thread_id, input_id) {
PendingUserInputClaim::Claimed(request) => request,
PendingUserInputClaim::Missing | PendingUserInputClaim::Settling => {
return Ok(false);
}
PendingUserInputClaim::Indeterminate => {
bail!(
"User-input request '{input_id}' has an indeterminate terminal receipt; inspect Runtime storage before retrying"
);
}
};
// This child task deliberately outlives the HTTP future. Once a
// request is claimed, client disconnect/cancellation cannot strand it
// between durable acceptance and engine delivery.View on GitHub (pinned to 0c42157ee5)
Solutions
- Check the thread exists and has a live engine before answering (poll thread status / pending requests first)
- If the engine legitimately ended, discard the stale request - the Ok(false) contract for Missing/Settling shows the runtime distinguishes this from hard errors
- Re-poll pending_requests_for_thread to confirm the input_id is still advertised before submitting
- Verify thread_id spelling and that the thread was started in this runtime session
Defensive patterns
Strategy: validation
Validate before calling
// Confirm the thread has a live engine before answering.
let thread = manager.get_thread(thread_id).await?; // hard error if the record is gone
if !manager.has_active_engine(thread_id).await { // or your equivalent liveness check
return Ok(()); // engine ended; drop the stale request
}
manager.submit_user_input(thread_id, input_id, response).await?; Try / catch
// Distinguish 'engine gone' (restartable) from real errors.
match manager.submit_user_input(thread_id, input_id, response).await {
Ok(accepted) => Ok(accepted),
Err(e) if e.to_string().contains("thread '") && e.to_string().contains("not found") => {
// Re-check thread state; restart it or discard the stale request.
Ok(false)
}
Err(e) => Err(e),
} Prevention
- Answer user-input requests promptly; engines end with their turns
- Re-poll pending requests right before answering to confirm the request is still advertised
- Never cache thread ids across runtime restarts
When it happens
Trigger: Calling submit_user_input after the turn/engine ended (the pending request expired with the engine), with a stale or mistyped thread_id, or before start_thread completed. See runtime_threads.rs:3274-3279.
Common situations: Client held a request id across a runtime restart and resumed answering after the engine shut down; race between turn completion and a late user response; thread archived or evicted by a workspace change between polling the request and answering.
Related errors
- User-input request '{}' has an indeterminate terminal receip
- User-input request '{input_id}' has an indeterminate termina
- runtime API returned {status}: {detail}
- unknown runtime backend `{other}` (use tmux|inline|vm|ci)
- tmux runtime is unavailable: `tmux -V` failed with {}: {}
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/dff1e9722590721c.
Report an issue: GitHub.