{"record":{"id":"8e7aea444069885e","repo":"coleam00/Archon","slug":"detached-run-control-path-is-not-a-directory-di","errorCode":null,"errorMessage":"Detached run control path is not a directory: ${directory}","messagePattern":"Detached run control path is not a directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/cli/src/utils/detached-run-control.ts","lineNumber":62,"sourceCode":"    this.name = 'DetachedRunOwnerUnavailableError';\n  }\n}\n\nfunction endpointToken(runId: string): string {\n  return createHash('sha256').update(runId).digest('hex').slice(0, 32);\n}\n\nfunction controlDirectory(): string {\n  const uid = process.getuid?.();\n  const directory =\n    process.platform === 'win32'\n      ? join(tmpdir(), 'archon-run-control')\n      : `/tmp/archon-${uid === undefined ? 'user' : String(uid)}`;\n  mkdirSync(directory, { recursive: true, mode: 0o700 });\n  if (process.platform !== 'win32') {\n    const stat = lstatSync(directory);\n    if (!stat.isDirectory() || stat.isSymbolicLink()) {\n      throw new Error(`Detached run control path is not a directory: ${directory}`);\n    }\n    if (uid !== undefined && stat.uid !== uid) {\n      throw new Error(`Detached run control directory is owned by another user: ${directory}`);\n    }\n    if ((stat.mode & 0o077) !== 0) {\n      throw new Error(`Detached run control directory must have mode 0700: ${directory}`);\n    }\n  }\n  return directory;\n}\n\n/** Prove the marked POSIX owner has the process group that active cancellation will signal. */\nexport function assertDetachedRunProcessOwner(): void {\n  if (process.platform !== 'win32' && !processGroupExists(process.pid)) {\n    throw new Error(\n      `Refusing detached run control because process ${String(process.pid)} does not own process group ${String(process.pid)}`\n    );\n  }","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/cli/src/utils/detached-run-control.ts#L44-L80","documentation":"controlDirectory() creates the detached-run control directory (e.g. /tmp/archon-<uid>) and then hardens it: on POSIX it lstats the path and requires a real directory (not a symlink) owned by the current user with mode 0700. This error fires when the path exists but is not a regular directory — typically a symlink or file planted at the expected location. It prevents a local attacker from redirecting control files through a symlink.","triggerScenarios":"lstatSync(directory) shows isDirectory() false or isSymbolicLink() true for the control directory path when a detached-run control path or lock path is resolved.","commonSituations":"Someone or something replaced /tmp/archon-<uid> with a symlink (often to another tmpfs or to attack the runtime); a file named archon-<uid> exists in /tmp from a misconfigured setup; a container volume mounts a file at that path.","solutions":["Inspect the path: ls -la /tmp/archon-* and confirm what it actually is.","Remove the file or symlink (it is a temp path, safe to delete when no run is active): rm /tmp/archon-<uid>, then let Archon recreate it.","Ensure nothing in your environment (mounts, provisioning scripts) pre-creates that path as a non-directory."],"exampleFix":"// before: path is a symlink\nlrwxrwxrwx archon-1000 -> /somewhere\n// after\nrm /tmp/archon-1000   # Archon recreates it as a 0700 directory","handlingStrategy":"try-catch","validationCode":"import { lstatSync } from 'node:fs';\nfunction controlDirLooksSafe(dir: string): boolean {\n  try { const st = lstatSync(dir); return st.isDirectory() && !st.isSymbolicLink(); }\n  catch { return true; } // absent is fine; Archon will create it\n}","typeGuard":"function isRealDirectory(st: import('node:fs').Stats): boolean {\n  return st.isDirectory() && !st.isSymbolicLink();\n}","tryCatchPattern":"try {\n  const dir = controlDirectory();\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Detached run control path is not a directory')) {\n    rmSync(expectedControlDir, { force: true, recursive: true });\n    // retry once\n  } else throw err;\n}","preventionTips":["Never symlink or pre-create /tmp/archon-<uid>.","Audit provisioning/container mounts for files placed at that path.","Run Archon as a consistent, unshared user."],"tags":["security","filesystem","posix","symlink"],"backgroundTag":"insecure-temp-directory","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}