{"record":{"id":"b53b8bbea6d354fb","repo":"EveryInc/compound-engineering-plugin","slug":"context-collectionpath-is-a-broken-symlink-ref-b53b8b","errorCode":null,"errorMessage":"${context.collectionPath} is a broken symlink; refusing to remove it automatically","messagePattern":"(.+?) is a broken symlink; refusing to remove it automatically","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/dev/codex-dev.ts","lineNumber":428,"sourceCode":"    return\n  }\n  await replaceManagedCollectionLink(context.collectionPath, previous.target, {\n    kind: \"valid\",\n    target: activatedTarget,\n  })\n}\n\nexport async function removeLocalCollection(context: CodexDevContext): Promise<boolean> {\n  const state = await inspectLocalCollection(context)\n  if (state.kind === \"absent\") return false\n  if (state.kind === \"collision\") {\n    throw new Error(`${context.collectionPath} exists and is not a symlink; refusing to remove it`)\n  }\n  if (state.kind === \"unrelated\") {\n    throw new Error(`${context.collectionPath} points outside a Compound Engineering checkout; refusing to remove it`)\n  }\n  if (state.kind === \"broken\") {\n    throw new Error(`${context.collectionPath} is a broken symlink; refusing to remove it automatically`)\n  }\n  await removeManagedCollectionLink(context.collectionPath, state.target)\n  return true\n}\n\nfunction parseJson<T>(result: CommandResult, label: string): T {\n  try {\n    return JSON.parse(result.stdout) as T\n  } catch (error) {\n    throw new Error(`${label} returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`)\n  }\n}\n\nasync function runCodex(\n  context: CodexDevContext,\n  runner: CommandRunner,\n  args: string[],\n): Promise<CommandResult> {","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/EveryInc/compound-engineering-plugin/blob/c9c10f8c75412c7232cb2bd663e5fd1cea98d84e/src/dev/codex-dev.ts#L410-L446","documentation":"removeLocalCollection() encounters a dangling symlink (target no longer exists) and refuses to remove it automatically. Unlike valid links, a broken link cannot be verified as Compound Engineering-owned, so an explicit manual step is required instead of a silent auto-delete.","triggerScenarios":"removeLocalCollection() (or switchToRemote / removeCodexDevInstallation) is called when collectionPath is a symlink whose realpath raises ENOENT — inspectLocalCollection returns kind='broken'.","commonSituations":"The linked checkout was deleted or moved after a previous local install; skillsRoot was on a removable/unmounted volume; a build script wiped the skills directory but left the symlink.","solutions":["Confirm the target is truly gone: `readlink <collectionPath>` then test the target path","Remove the dangling link manually: `rm <collectionPath>`","Restore the checkout first instead (re-clone / remount) if you want to keep local mode","Re-run the codex:dev command to establish the desired state"],"exampleFix":"# before\n$ bun run codex:dev -- remote\n# Error: ... is a broken symlink; refusing to remove it automatically\n\n# after\n$ rm /path/to/CODEX_HOME/skills/compound-engineering-local  # target already gone\n$ bun run codex:dev -- remote","handlingStrategy":"try-catch","validationCode":"const state = await inspectLocalCollection(context);\nif (state.kind === \"broken\") {\n  console.log(`dangling link to ${state.target}; safe to rm the link`);\n}","typeGuard":"function isDanglingLink(s: { kind: string; target?: string }): s is { kind: \"broken\"; target: string } {\n  return s.kind === \"broken\" && typeof s.target === \"string\";\n}","tryCatchPattern":"try {\n  await removeLocalCollection(context);\n} catch (e) {\n  if (String(e).includes(\"broken symlink\")) {\n    await fs.unlink(context.collectionPath); // target already gone; deleting the link is safe\n    await removeLocalCollection(context);\n  } else throw e;\n}","preventionTips":["Do not delete checkouts that are symlink targets without first switching to remote","Re-point or recreate links after moving a checkout","Run `bun run codex:dev -- status` to detect broken state early"],"tags":["symlink","broken-symlink","filesystem","codex-dev"],"backgroundTag":"broken-symlink","analyzedSha":"c9c10f8c75412c7232cb2bd663e5fd1cea98d84e","analyzedAt":"2026-08-31T15:18:07.959Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}