Hmbown/CodeWhale · error

Dynamic tool call '{call_id}' has an indeterminate terminal

Error message

Dynamic tool call '{call_id}' has an indeterminate terminal receipt; inspect Runtime storage before retrying

What it means

submit_dynamic_tool_result (or the turn path) claimed call_id for (thread_id, turn_id) and got PendingDynamicToolClaim::Indeterminate: the entry's terminal receipt append failed and rolled back uncleanly, so the JSONL log may already contain the terminal line. The runtime refuses a resubmission because a duplicate terminal receipt could be appended.

Source

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

            Some(entry) => entry.sender.send(decision).is_ok(),
            None => false,
        }
    }

    pub async fn deliver_dynamic_tool_result(
        &self,
        thread_id: &str,
        turn_id: &str,
        call_id: &str,
        result: DynamicToolCallResult,
    ) -> Result<bool> {
        let claim = match self.claim_pending_dynamic_tool(thread_id, turn_id, call_id) {
            PendingDynamicToolClaim::Claimed(claim) => claim,
            PendingDynamicToolClaim::Settling(_) | PendingDynamicToolClaim::Missing => {
                return Ok(false);
            }
            PendingDynamicToolClaim::Indeterminate => {
                bail!(
                    "Dynamic tool call '{call_id}' has an indeterminate terminal receipt; inspect Runtime storage before retrying"
                );
            }
        };
        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 = {

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Stop retrying the submit - the call is frozen in an indeterminate tombstone by design
  2. Inspect the thread's JSONL event log to see whether tool_call.resolved / tool_call.canceled / tool_call.timeout was durably written for this call_id
  3. Repair the storage cause, then reconcile or remove the tombstoned entry via runtime restart / storage reconciliation
  4. Preserve the inspected evidence; it tells you whether the model ever received the result
Defensive patterns

Strategy: try-catch

Try / catch

// Indeterminate receipt: stop, never resubmit, escalate.
match manager.submit_dynamic_tool_result(thread_id, turn_id, call_id, result).await {
    Ok(accepted) => Ok(accepted),
    Err(e) if e.to_string().contains("indeterminate terminal receipt") => {
        tracing::error!(%call_id, "result state unknown; inspect Runtime storage before any retry");
        Err(e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Retrying submit_dynamic_tool_result after the first attempt's settlement task hit a non-retry-safe RuntimeEventAppendError (mark_dynamic_tool_claim_indeterminate ran). Also reached from turn completion touching the same call. See runtime_threads.rs:3246-3257 and claim_pending_dynamic_tool:3113.

Common situations: Storage failure (ENOSPC, EACCES) during the first result append; process crash between append and rollback; client-side auto-retry of a timed-out HTTP submit.

Related errors


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