{"record":{"id":"b43f8dc61d16ca80","repo":"shareAI-lab/learn-claude-code","slug":"worktree-name-already-exists-in-index","errorCode":null,"errorMessage":"Worktree '{name}' already exists in index","messagePattern":"Worktree '(.+?)' already exists in index","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agents/s12_worktree_task_isolation.py","lineNumber":287,"sourceCode":"        self.index_path.write_text(json.dumps(data, indent=2))\n\n    def _find(self, name: str) -> dict | None:\n        idx = self._load_index()\n        for wt in idx.get(\"worktrees\", []):\n            if wt.get(\"name\") == name:\n                return wt\n        return None\n\n    def _validate_name(self, name: str):\n        if not re.fullmatch(r\"[A-Za-z0-9._-]{1,40}\", name or \"\"):\n            raise ValueError(\n                \"Invalid worktree name. Use 1-40 chars: letters, numbers, ., _, -\"\n            )\n\n    def create(self, name: str, task_id: int = None, base_ref: str = \"HEAD\") -> str:\n        self._validate_name(name)\n        if self._find(name):\n            raise ValueError(f\"Worktree '{name}' already exists in index\")\n        if task_id is not None and not self.tasks.exists(task_id):\n            raise ValueError(f\"Task {task_id} not found\")\n\n        path = self.dir / name\n        branch = f\"wt/{name}\"\n        self.events.emit(\n            \"worktree.create.before\",\n            task={\"id\": task_id} if task_id is not None else {},\n            worktree={\"name\": name, \"base_ref\": base_ref},\n        )\n        try:\n            self._run_git([\"worktree\", \"add\", \"-b\", branch, str(path), base_ref])\n\n            entry = {\n                \"name\": name,\n                \"path\": str(path),\n                \"branch\": branch,\n                \"task_id\": task_id,","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/shareAI-lab/learn-claude-code/blob/985456f4adea6f4df8fbad4112245dbd97444eae/agents/s12_worktree_task_isolation.py#L269-L305","documentation":"Thrown by WorktreeManager.create when _find(name) locates an entry with the same name in the persisted worktree index JSON. Creation is idempotent-hostile by design: each worktree name maps to one directory (self.dir / name) and one branch (wt/{name}), so a duplicate would overwrite state. The check reads the index file, so it also fires when a previous worktree was created but never removed from the index.","triggerScenarios":"Calling create(\"feature-x\") twice without a matching remove/delete in between; a prior create that succeeded on disk but whose caller crashed before the flow completed, leaving the index entry behind; two agents racing to create the same-named worktree.","commonSituations":"Retrying a failed orchestration step that re-runs the same create call; stale index entries after interrupted cleanup; deriving the same slug from two different task subjects that sanitize to an identical name.","solutions":["If the existing worktree is still wanted, reuse its entry from the index instead of creating a new one","If it is stale, call the manager's remove/delete flow for that name first, then create again","Make names unique per task, e.g. f\"task-{task_id}-{slug}\", so parallel tasks cannot collide","Catch ValueError and inspect the index entry to decide reuse-vs-replace programmatically"],"exampleFix":"// before\nwt.create(name=\"feature-x\", task_id=7)  # raises on retry\n// after\nexisting = wt._find(\"feature-x\")\nif existing:\n    result = existing[\"path\"]  # reuse\nelse:\n    result = wt.create(name=\"feature-x\", task_id=7)","handlingStrategy":"validation","validationCode":"entry = wt._find(name)\nif entry:\n    use_path = entry[\"path\"]  # reuse instead of create\nelse:\n    use_path = wt.create(name, task_id=tid)","typeGuard":null,"tryCatchPattern":"try:\n    path = wt.create(name, task_id=tid)\nexcept ValueError as e:\n    if 'already exists' in str(e):\n        existing = wt._find(name)\n        if existing and stale(existing):\n            wt.remove(name)\n            path = wt.create(name, task_id=tid)\n        else:\n            path = existing[\"path\"]\n    else:\n        raise","preventionTips":["Make worktree names unique per task (include task_id in the name)","Always pair create with a matching remove in cleanup/finally blocks","Treat create as get-or-create: check the index first"],"tags":["worktree","duplicate","state-management","git"],"backgroundTag":null,"analyzedSha":"985456f4adea6f4df8fbad4112245dbd97444eae","analyzedAt":"2026-08-14T22:02:26.028Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}