coleam00/Archon · critical
Detached run control path is not a directory: ${directory}
Error message
Detached run control path is not a directory: ${directory} What it means
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.
Source
Thrown at packages/cli/src/utils/detached-run-control.ts:62
this.name = 'DetachedRunOwnerUnavailableError';
}
}
function endpointToken(runId: string): string {
return createHash('sha256').update(runId).digest('hex').slice(0, 32);
}
function controlDirectory(): string {
const uid = process.getuid?.();
const directory =
process.platform === 'win32'
? join(tmpdir(), 'archon-run-control')
: `/tmp/archon-${uid === undefined ? 'user' : String(uid)}`;
mkdirSync(directory, { recursive: true, mode: 0o700 });
if (process.platform !== 'win32') {
const stat = lstatSync(directory);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new Error(`Detached run control path is not a directory: ${directory}`);
}
if (uid !== undefined && stat.uid !== uid) {
throw new Error(`Detached run control directory is owned by another user: ${directory}`);
}
if ((stat.mode & 0o077) !== 0) {
throw new Error(`Detached run control directory must have mode 0700: ${directory}`);
}
}
return directory;
}
/** Prove the marked POSIX owner has the process group that active cancellation will signal. */
export function assertDetachedRunProcessOwner(): void {
if (process.platform !== 'win32' && !processGroupExists(process.pid)) {
throw new Error(
`Refusing detached run control because process ${String(process.pid)} does not own process group ${String(process.pid)}`
);
}View on GitHub (pinned to 0773b97458)
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.
Example fix
// before: path is a symlink lrwxrwxrwx archon-1000 -> /somewhere // after rm /tmp/archon-1000 # Archon recreates it as a 0700 directory
Defensive patterns
Strategy: try-catch
Validate before calling
import { lstatSync } from 'node:fs';
function controlDirLooksSafe(dir: string): boolean {
try { const st = lstatSync(dir); return st.isDirectory() && !st.isSymbolicLink(); }
catch { return true; } // absent is fine; Archon will create it
} Type guard
function isRealDirectory(st: import('node:fs').Stats): boolean {
return st.isDirectory() && !st.isSymbolicLink();
} Try / catch
try {
const dir = controlDirectory();
} catch (err) {
if (err instanceof Error && err.message.startsWith('Detached run control path is not a directory')) {
rmSync(expectedControlDir, { force: true, recursive: true });
// retry once
} else throw err;
} Prevention
- 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.
When it happens
Trigger: lstatSync(directory) shows isDirectory() false or isSymbolicLink() true for the control directory path when a detached-run control path or lock path is resolved.
Common situations: 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.
Related errors
- Detached run control directory is owned by another user: ${d
- Detached run control directory must have mode 0700: ${direct
- Checksum mismatch: expected ${expectedHash}, got ${actualHas
- tar extraction failed (exit ${exitCode}): ${details}
- Failed to move extracted web UI from ${tmpDir} to ${targetDi
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/8e7aea444069885e.
Report an issue: GitHub.