{"record":{"id":"51eb5606b8c9f2c3","repo":"JuliusBrussee/caveman","slug":"mcp-config-path-contains-dangling-symlink-ancest","errorCode":null,"errorMessage":"MCP config path contains dangling symlink ${ancestor}; refusing mutation","messagePattern":"MCP config path contains dangling symlink (.+?); refusing mutation","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":10866,"sourceCode":"  agent: \"kilo\" | \"qwen\";\n  path: string;\n  before: Buffer | null;\n  beforeMode: number;\n  after: Buffer | null;\n  changed: boolean;\n};\n\nfunction canonicalMcpConfigPath(path: string): string {\n  const absolute = normalize(resolve(path));\n  const missing: string[] = [];\n  let ancestor = absolute;\n  while (true) {\n    try {\n      return normalize(join(realpathSync(ancestor), ...missing));\n    } catch {\n      try {\n        if (lstatSync(ancestor).isSymbolicLink()) {\n          throw new Error(`MCP config path contains dangling symlink ${ancestor}; refusing mutation`);\n        }\n      } catch (error) {\n        if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n      }\n      const parent = dirname(ancestor);\n      if (parent === ancestor) return absolute;\n      missing.unshift(basename(ancestor));\n      ancestor = parent;\n    }\n  }\n}\n\nfunction ownedMcpConfigPlan(\n  agent: \"kilo\" | \"qwen\",\n  path: string,\n  loaded: { bytes: Buffer | null; exists: boolean },\n  after: Buffer | null,\n): OwnedMcpConfigPlan {","sourceCodeStart":10848,"sourceCodeEnd":10884,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/5184b3d11ac6a1acb7d44b9bfaa31698157cff97/packages/cli/src/index.ts#L10848-L10884","documentation":"Guard inside canonicalMcpConfigPath: while walking the path's ancestors to resolve it to a canonical real path, an ancestor exists as a symbolic link but realpathSync failed on it, meaning the link is dangling (points to a nonexistent target). Writing through it could create files in unexpected places, so mutation is refused.","triggerScenarios":"Thrown at packages/cli/src/index.ts:10866 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Fix or remove the dangling symlink named in the message so it points to an existing target","Repoint the MCP config location (KILO_CONFIG_DIR, XDG_CONFIG_HOME, or the agent's config path) to a real directory","Create the symlink's target directory if it was intended to exist"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"5184b3d11ac6a1acb7d44b9bfaa31698157cff97","analyzedAt":"2026-09-06T12:00:26.372Z","contentChangedAt":"2026-09-06T12:00:26.372Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}