{"record":{"id":"6a21e0f170485954","repo":"Hmbown/CodeWhale","slug":"thread-execution-settings-changed-while-preparing","errorCode":null,"errorMessage":"Thread execution settings changed while preparing the turn; retry","messagePattern":"Thread execution settings changed while preparing the turn; retry","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_threads.rs","lineNumber":10249,"sourceCode":"                && let Some(original_turn) = self.replay_turn_for_operation(operation)?\n            {\n                return Ok((original_turn, true));\n            }\n            let Some(state) = active.engines.get_mut(thread_id) else {\n                bail!(\"Thread engine not loaded\");\n            };\n            if state.active_turn.is_some() {\n                bail!(\"Thread already has an active turn\");\n            }\n            let _goal_mutation = self.store.goal_mutation.lock();\n            if self.store.load_goal(thread_id)? != turn_goal {\n                bail!(\"Goal changed while preparing the turn; retry\");\n            }\n            engine.restore_runtime_goal(turn_goal.as_ref())?;\n            let _thread_mutation = self.store.thread_mutation.lock();\n            let mut current_thread = self.store.load_thread(thread_id)?;\n            if !thread_execution_state_matches(&thread, &current_thread) {\n                bail!(\"Thread execution settings changed while preparing the turn; retry\");\n            }\n            let previous_active_route = (state.route_identity.clone(), state.route_model.clone());\n            state.active_turn = Some(ActiveTurnState {\n                goal_id: turn_goal.as_ref().map(|goal| goal.goal_id.clone()),\n                turn_id: turn_id.clone(),\n                interrupt_requested: false,\n                compaction_id: None,\n            });\n            state.route_identity = provider_identity;\n            state.route_model.clone_from(&model);\n\n            let persistence_result = (|| -> Result<()> {\n                if let Some(operation) = operation.as_ref() {\n                    self.store\n                        .save_turn_operation_binding(&operation.binding)?;\n                }\n                self.store.save_item(&user_item)?;\n                self.store.save_turn(&turn)?;","sourceCodeStart":10231,"sourceCodeEnd":10267,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_threads.rs#L10231-L10267","documentation":"After goal verification, the runtime reloads the thread record under the thread-mutation lock and compares its execution settings (model, route, etc.) with the snapshot the request was built from via thread_execution_state_matches. A mismatch means the thread's configuration moved mid-flight, so the turn is refused rather than run with stale settings.","triggerScenarios":"Changing the thread's model/execution settings (e.g. via a settings API or UI switch) after the request snapshot was taken but before turn registration completed.","commonSituations":"User flips model or provider mid-submission; a background job rewrites thread config; hot-swapping route settings while a queued turn fires.","solutions":["Retry with a freshly loaded thread so the request snapshot matches current settings.","Avoid changing thread execution settings while a turn is being prepared.","If the change was intentional, cancel the in-flight submission and start a new turn from current state."],"exampleFix":"// before\nlet thread = store.load_thread(id)?;\nspawn(set_thread_model(id, \"new-model\"));\nsubmit_turn(thread, req)?; // may mismatch\n// after\nlet thread = store.load_thread(id)?;\nsubmit_turn(thread, req).await?;\nset_thread_model(id, \"new-model\").await?;","handlingStrategy":"retry","validationCode":"let current = store.load_thread(thread_id)?;\nif !thread_execution_state_matches(&thread_snapshot, &current) {\n    thread_snapshot = current; // rebuild request from fresh thread\n}","typeGuard":null,"tryCatchPattern":"match submit_turn(id, req).await {\n    Err(e) if e.to_string().contains(\"settings changed\") => {\n        let fresh = store.load_thread(id)?;\n        submit_turn(id, req_for(fresh)).await\n    }\n    other => other,\n}","preventionTips":["Pause settings/model changes while a turn submission is in flight.","Apply execution-setting changes only between turns.","Always load the thread record at submission time rather than caching it."],"tags":["concurrency","config-drift","retryable"],"backgroundTag":"invalid-state-transition","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}