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, &current_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(&current_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

  1. Retry compaction — it re-reads thread settings from the fresh record
  2. Apply execution-settings changes only when the thread is idle to avoid racing turns/compactions
  3. Serialize settings updates with compaction via the same mutation queue
  4. 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

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


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