Hmbown/CodeWhale · error
operation_key is already bound to a different turn request
Error message
operation_key is already bound to a different turn request
What it means
Turn operation idempotency check: the operation_key's stored binding (thread, key fingerprint, request fingerprint, or requested turn) differs from the incoming request — the same key is being replayed with different content, which would silently alias two different turns.
Solutions
- Use a distinct operation_key for the new turn request, or reuse the exact original request for a replay.
- Treat the persisted turn as the authoritative result of the earlier operation key.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at crates/tui/src/runtime_threads.rs:9064 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/675525b1499ddfbd.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/runtime_threads.rs:9064
&self,
prepared: &PreparedRuntimeTurnOperation,
) -> Result<Option<TurnRecord>> {
let requested = &prepared.binding;
let Some(persisted) = self
.store
.load_turn_operation_binding(&requested.operation_key_fingerprint)?
else {
return Ok(None);
};
if persisted.thread_id != requested.thread_id
|| persisted.operation_key_fingerprint != requested.operation_key_fingerprint
|| persisted.request_fingerprint != requested.request_fingerprint
|| prepared
.requested_turn_id
.as_deref()
.is_some_and(|turn_id| persisted.turn_id != turn_id)
{
bail!("operation_key is already bound to a different turn request");
}
let turn_path = self.store.turn_path(&persisted.turn_id)?;
if !turn_path.exists() {
bail!("operation_key binding is incomplete; retry after Runtime recovery");
}
let turn = self.store.load_turn(&persisted.turn_id)?;
if turn.id != persisted.turn_id || turn.thread_id != persisted.thread_id {
bail!("operation_key binding does not match its persisted Runtime turn");
}
Ok(Some(turn))
}
/// Read the exact durable binding without replaying, recovering, loading an
/// engine, or creating even a claim-lock file. The shared claim prevents a
/// reader from observing admission records that can still be rolled back.
pub(crate) fn lookup_turn_operation(
&self,
thread_id: &str,View on GitHub (pinned to 73e0f67d83)