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
- Stop retrying the submit - the call is frozen in an indeterminate tombstone by design
- 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
- Repair the storage cause, then reconcile or remove the tombstoned entry via runtime restart / storage reconciliation
- 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
- Do not auto-retry result submission after storage errors - a failed rollback freezes the call
- Keep the runtime store healthy (space, permissions) so appends never enter the failed-rollback path
- Log both call_id and turn_id with submissions so an incident can be traced to the exact JSONL line
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
- User-input request '{input_id}' has an indeterminate termina
- Turn {turn_id} has an indeterminate dynamic-tool receipt; re
- User-input request '{}' has an indeterminate terminal receip
- Dynamic tool call '{}' is already pending
- {error}
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/ce3b0d0825bbc86a.
Report an issue: GitHub.