Hmbown/CodeWhale · error · anyhow::Error
Thread execution settings changed while preparing compaction
Error message
Thread execution settings changed while preparing compaction; retry
What it means
compact_thread re-loads the thread under the thread_mutation lock and compares it with the snapshot taken at call entry via thread_execution_state_matches (crates/tui/src/runtime_threads.rs:6431). A mismatch means execution-relevant settings (route/model/sandbox and friends) were changed on disk while the compaction was being prepared, so the armed compaction would run against stale settings; abort and retry.
Source
Thrown at crates/tui/src/runtime_threads.rs:6431
route: Box::new(route),
compaction: Box::new(compaction),
};
let permit = engine.tx_op.clone().reserve_owned().await.map_err(|_| {
anyhow!("Failed to trigger compaction: engine operation channel closed")
})?;
let acceptance_rx = {
let mut active = self.active.lock().await;
let Some(state) = active.engines.get_mut(thread_id) else {
bail!("Thread engine not loaded");
};
if state.active_turn.is_some() {
bail!("Thread already has an active turn");
}
let _thread_mutation = self.store.thread_mutation.lock();
let mut current_thread = self.store.load_thread(thread_id)?;
if !thread_execution_state_matches(&thread, ¤t_thread) {
bail!("Thread execution settings changed while preparing compaction; retry");
}
let previous_active_route = (state.route_identity.clone(), state.route_model.clone());
state.active_turn = Some(ActiveTurnState {
turn_id: turn_id.clone(),
interrupt_requested: false,
compaction_id: Some(compaction_id),
});
state.route_identity = route_identity;
state.route_model = route_model;
let persistence_result = (|| -> Result<()> {
self.store.save_turn(&turn)?;
current_thread.latest_turn_id = Some(turn_id.clone());
current_thread.updated_at = now;
self.store.save_thread(¤t_thread)
})();
if let Err(persistence_error) = persistence_result {
let cleanup_error = self.cleanup_unaccepted_turn_records(&turn_id, None).err();View on GitHub (pinned to 0c42157ee5)
Solutions
- Retry compaction — it re-reads thread settings from the fresh record
- Apply execution-settings changes only when the thread is idle to avoid racing turns/compactions
- Serialize settings updates with compaction via the same mutation queue
- If persistent, verify nothing is rewriting thread records in a loop
Example fix
// before
let turn = runtime.compact_thread(&thread_id, req).await?;
// after
let turn = loop {
match runtime.compact_thread(&thread_id, req.clone()).await {
Ok(t) => break t,
Err(e) if e.to_string().contains("settings changed") => continue, // re-read + retry
Err(e) => return Err(e),
}
}; Defensive patterns
Strategy: retry
Validate before calling
// Refresh the thread snapshot right before compacting so settings are current. let thread = runtime.get_thread(thread_id).await?; assert_execution_settings_stable(&thread).await?; runtime.compact_thread(thread_id, req).await
Try / catch
let mut attempts = 0;
loop {
match runtime.compact_thread(thread_id, req.clone()).await {
Ok(turn) => break Ok(turn),
Err(err) if attempts < 3 && err.to_string().contains("settings changed") => {
attempts += 1;
continue; // next attempt re-reads thread settings
}
Err(err) => return Err(err),
}
} Prevention
- Apply execution-settings changes only when the thread is idle
- Route settings mutations and compaction through the same serialization point
- Re-read thread state immediately before expensive operations
- Alert if settings flap repeatedly — something is rewriting thread records
When it happens
Trigger: User changes model/route/sandbox settings while compaction start is in flight; another client edits the thread record; settings sync applying concurrently with compact.
Common situations: Settings UI applying changes just as the user clicks Compact; automation flipping routes mid-operation; shared thread edited from a second session.
Related errors
- Thread engine changed while preparing steer; retry
- new Date()/Date() is unavailable in Workflow scripts: runs m
- permissions changed after they were listed; reload {} and re
- xAI OAuth lifecycle lock changed repeatedly while opening
- Fleet worker {worker_id} coordination state is busy; retry r
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/a4e42789aac49fc8.
Report an issue: GitHub.