Hmbown/CodeWhale · error · anyhow::Error

User-input request '{input_id}' has an indeterminate termina

Error message

User-input request '{input_id}' has an indeterminate terminal receipt; inspect Runtime storage before retrying

What it means

submit_user_input claimed input_id and got PendingUserInputClaim::Indeterminate: a previous answer attempt for this request hit a failed append whose rollback also failed, leaving entry.indeterminate = true. The runtime refuses to accept or re-deliver an answer whose durable receipt cannot be established, because either action could duplicate or disclose a response.

Source

Thrown at crates/tui/src/runtime_threads.rs:3284

        &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.
        let manager = self.clone();
        let thread_id = thread_id.to_string();
        tokio::spawn(async move {
            manager
                .settle_claimed_user_input(
                    &thread_id,
                    Some(engine),
                    request,
                    UserInputTerminalOutcome::Answered(response),
                )

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Do not retry the same input_id - the tombstone is intentional
  2. Inspect the runtime store's JSONL log for the user_input answer receipt to learn whether the first attempt committed
  3. Fix the underlying storage problem, then restart/reconcile the runtime so pending state is rebuilt from disk
  4. Design the client to treat 'unknown outcome' as an operator-visible incident, not a retryable error
Defensive patterns

Strategy: try-catch

Try / catch

// The indeterminate bail is terminal for this input_id - escalate.
match manager.submit_user_input(thread_id, input_id, response).await {
    Ok(accepted) => Ok(accepted),
    Err(e) if e.to_string().contains("indeterminate terminal receipt") => {
        tracing::error!(%input_id, "answer receipt unknown; inspect Runtime storage");
        Err(e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Retrying submit_user_input with the same input_id after the first attempt's spawned delivery task failed non-retry-safely (mark_pending_user_input_indeterminate ran). Guard at runtime_threads.rs:3284-3287, flag logic at :2993-3013.

Common situations: Storage I/O failure during the first submit; automatic client retry after an HTTP timeout where the server may have already committed; process kill mid-append.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/2cccba615cc61490. Report an issue: GitHub.