{"record":{"id":"0006ed0b3277beae","repo":"HKUDS/Vibe-Trading","slug":"expected-goal-id-does-not-match-target-goal","errorCode":null,"errorMessage":"expected_goal_id does not match target goal","messagePattern":"expected_goal_id does not match target goal","errorType":"validation","errorClass":"StaleGoalError","httpStatus":null,"severity":"error","filePath":"agent/src/goal/store.py","lineNumber":832,"sourceCode":"                    now,\n                    goal_id,\n                    session_id,\n                ),\n            )\n\n        updated = self.get_goal(goal_id)\n        if updated is None:\n            raise RuntimeError(\"usage-updated goal could not be reloaded\")\n        return updated\n\n    def _require_mutable_goal(\n        self,\n        session_id: str,\n        goal_id: str,\n        expected_goal_id: str,\n    ) -> GoalRecord:\n        if expected_goal_id != goal_id:\n            raise StaleGoalError(\"expected_goal_id does not match target goal\")\n        session_id = normalize_required_text(session_id, \"session_id\")\n        goal_id = normalize_required_text(goal_id, \"goal_id\")\n        goal = self.get_goal(goal_id)\n        if goal is None or goal.session_id != session_id:\n            raise StaleGoalError(\"goal is not available for this session\")\n        if goal.status not in _CURRENT_STATUSES:\n            raise StaleGoalError(f\"goal status {goal.status.value!r} is not mutable\")\n        current = self.get_current_goal(session_id)\n        if current is None or current.goal_id != goal_id:\n            raise StaleGoalError(\"goal is not current for this session\")\n        return goal\n\n    @staticmethod\n    def _verification_status(evidence: EvidenceInput) -> str:\n        \"\"\"Return whether evidence has a traceable local artifact/run source.\"\"\"\n        if evidence.artifact_path:\n            try:\n                artifact = safe_document_path(evidence.artifact_path)","sourceCodeStart":814,"sourceCodeEnd":850,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/goal/store.py#L814-L850","documentation":"Thrown by GoalStore._require_mutable_goal when the expected_goal_id passed for optimistic concurrency does not equal the target goal_id. The store requires callers to prove they are acting on the goal version they last saw; a mismatch means the client's reference is stale or simply wrong.","triggerScenarios":"Calling update_goal, append_evidence, update_status, or account_usage with expected_goal_id != goal_id, e.g. after the session's current goal has switched and the client reuses an old expected id.","commonSituations":"Agent loop holds a cached goal id after a new goal was created; concurrent writers racing on the same session; copy-paste of ids between sessions.","solutions":["Re-fetch the session's current goal (get_current_goal) and retry with its goal_id as expected_goal_id","If racing another writer, resolve the conflict first — decide whether the stale operation should be dropped or re-applied to the new goal","Add a pre-call check expected_goal_id == goal_id to fail fast in client code"],"exampleFix":"// before\nstore.update_goal(session_id, goal_id=gid, expected_goal_id=old_gid, ...)\n// after\ncurrent = store.get_current_goal(session_id)\nif current is None or current.goal_id != gid:\n    gid = current.goal_id\nstore.update_goal(session_id, goal_id=gid, expected_goal_id=gid, ...)","handlingStrategy":"validation","validationCode":"goal = store.get_goal(goal_id)\nif goal is None or goal.goal_id != expected_goal_id:\n    current = store.get_current_goal(session_id)\n    goal_id = expected_goal_id = current.goal_id if current else None","typeGuard":"def is_fresh_goal_ref(store, session_id: str, goal_id: str, expected: str) -> bool:\n    return expected == goal_id and (store.get_current_goal(session_id) or object()).goal_id == goal_id","tryCatchPattern":"except StaleGoalError: refresh current goal from store and retry once; escalate if it persists","preventionTips":["Always derive goal_id from get_current_goal rather than caching","Pass expected_goal_id == goal_id by construction","Refresh goal refs after any operation that can create goals"],"tags":["goal-store","optimistic-concurrency","stale-state","python"],"backgroundTag":"optimistic-concurrency-conflict","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}