Hmbown/CodeWhale · error
Runtime Chat binding state contains duplicate thread…
Error message
Runtime Chat binding state contains duplicate thread authority
What it means
RelayState::validate enforces uniqueness of thread authority identifiers: runtime_binding_id, virtual_thread_id, and native_thread_id must each be unique across all bindings in the state. A duplicate means two bindings claim the same thread identity, which would make routing ambiguous, so persistence is refused.
Solutions
- Remove or regenerate the duplicate binding so each runtime_binding_id, virtual_thread_id, and native_thread_id is unique
- Regenerate the virtual thread id (local_thread_ + fresh hex) for the second binding
- Deduplicate bindings before constructing RelayState (e.g. with a HashSet keyed on the ids)
- Fix the id-generation code that produced a collision
Example fix
// before state.bindings.push(binding.clone()); // same ids as an existing binding // after binding.virtual_thread_id = new_virtual_thread_id(); binding.native_thread_id = new_native_thread_id(); state.bindings.push(binding);
Defensive patterns
Strategy: validation
Validate before calling
fn ensure_unique_authority(state: &RelayState) -> Result<()> {
let mut seen = std::collections::HashSet::new();
for b in &state.bindings {
for id in [&b.runtime_binding_id, &b.virtual_thread_id, &b.native_thread_id] {
if !seen.insert(id.clone()) {
anyhow::bail!("duplicate thread authority: {id}");
}
}
}
Ok(())
} Type guard
fn bindings_have_unique_authority(state: &RelayState) -> bool {
let ids: Vec<_> = state.bindings.iter()
.flat_map(|b| [&b.runtime_binding_id, &b.virtual_thread_id, &b.native_thread_id])
.collect();
ids.iter().collect::<std::collections::HashSet<_>>().len() == ids.len()
} Try / catch
if let Err(e) = relay.persist_state(&state) {
if e.to_string().contains("duplicate thread authority") {
// regenerate ids for the offending binding and retry once
} else { return Err(e); }
} Prevention
- Always allocate ids from the single local id generator; never clone bindings with their ids
- Deduplicate bindings against existing state before insertion
- Key in-memory bindings by (virtual_thread_id, native_thread_id) so duplicates surface early
When it happens
Trigger: Calling persist_state (or the persisted_binding_state_rejects_duplicate_or_nonopaque_authority test) with a RelayState containing two bindings that share any of runtime_binding_id, virtual_thread_id, or native_thread_id.
Common situations: Copy-pasting a binding in test fixtures; a merge of two state files that produced overlapping ids; a bug that regenerates the same virtual thread id for two runs; restoring state where a new binding reused an old id.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid coordination ledger
- Invalid pet score checkpoint.
- Invalid pet score checkpoint.
- Invalid pet state.
- Runtime Chat binding state has no account owner
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/02284af926f3f26a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/runtime_chat_relay.rs:231
let mut virtual_threads = HashSet::new();
let mut native_threads = HashSet::new();
for binding in &self.bindings {
validate_relay_id(&binding.run_id, "run id")?;
validate_relay_id(&binding.runtime_binding_id, "binding id")?;
validate_virtual_thread_id(&binding.virtual_thread_id)?;
validate_native_record_id(&binding.native_thread_id, "native thread id")?;
validate_route_id(&binding.model_provider, "provider id")?;
validate_route_id(&binding.model_provider_id, "model-provider id")?;
validate_model_id(&binding.model)?;
validate_fingerprint(&binding.first_operation_fingerprint)?;
if let Some(fingerprint) = binding.system_prompt_fingerprint.as_deref() {
validate_fingerprint(fingerprint)?;
}
if !binding_ids.insert(binding.runtime_binding_id.clone())
|| !virtual_threads.insert(binding.virtual_thread_id.clone())
|| !native_threads.insert(binding.native_thread_id.clone())
{
bail!("Runtime Chat binding state contains duplicate thread authority");
}
for (virtual_turn_id, turn) in &binding.turns {
validate_virtual_turn_id(virtual_turn_id)?;
validate_native_record_id(&turn.native_turn_id, "native turn id")?;
validate_fingerprint(&turn.operation_fingerprint)?;
validate_fingerprint(&turn.request_fingerprint)?;
}
}
Ok(())
}
}
impl RuntimeChatRelayHost {
pub(crate) fn open(
config: Config,
_plugin_registry: Arc<PluginRegistry>,
private_root: PathBuf,
target_ref: String,View on GitHub (pinned to 73e0f67d83)