{"record":{"id":"0495eb3471d3eaf3","repo":"Hmbown/CodeWhale","slug":"goal-changed-while-preparing-the-turn-retry","errorCode":null,"errorMessage":"Goal changed while preparing the turn; retry","messagePattern":"Goal changed while preparing the turn; retry","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_threads.rs","lineNumber":10243,"sourceCode":"                .transpose()?;\n            // A concurrent exact retry may have crossed the first lookup\n            // before the original request committed its binding. Recheck\n            // under the same claim lock before inspecting active-turn state or\n            // persisting/sending anything.\n            if let Some(operation) = operation.as_ref()\n                && 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<()> {","sourceCodeStart":10225,"sourceCodeEnd":10261,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_threads.rs#L10225-L10261","documentation":"While preparing the turn, the runtime re-reads the thread's goal under the goal-mutation lock and compares it to the goal captured at request time. If the goal changed concurrently, preparation is aborted with this retryable error to avoid running a turn against a goal the user no longer set.","triggerScenarios":"Another task/user updated the thread's stored goal (store.update_goal) between turn submission and the locked re-read inside turn preparation.","commonSituations":"User edits the thread goal while a turn is being submitted; an automation rewrites goals concurrently with a scheduled turn; retry storms after a first failed preparation.","solutions":["Retry the turn submission; the error is explicitly a retry hint.","Re-fetch the thread and its current goal, then resubmit with fresh state.","Stop mutating the thread goal while turns are being submitted (or pause goal edits during runs)."],"exampleFix":"// before\nmatch runtime.submit_turn(t, req) { Err(_) => panic!(), ... }\n// after\nmatch runtime.submit_turn(t, req) {\n    Err(e) if e.contains(\"retry\") => runtime.submit_turn(t, refresh(req)).await?,\n    other => other?,\n}","handlingStrategy":"retry","validationCode":"let goal_now = store.load_goal(thread_id)?;\nif goal_now != turn_goal {\n    // resubmit with fresh state before calling the API\n}","typeGuard":null,"tryCatchPattern":"match submit_turn(id, req).await {\n    Err(e) if e.to_string().contains(\"retry\") => submit_turn(id, req_fresh()).await,\n    other => other,\n}","preventionTips":["Lock goal edits while turns are being submitted.","Refresh the thread snapshot immediately before each submission attempt.","Treat 'retry' errors as expected and add bounded retry logic."],"tags":["concurrency","goal-mutation","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"}