coleam00/Archon · critical

Detached run control directory is owned by another user: ${d

Error message

Detached run control directory is owned by another user: ${directory}

What it means

After creating the detached-run control directory, controlDirectory() verifies on POSIX that the directory's owning uid matches the current process uid. If another user owns the path, the runtime refuses to use it, since control files there (lock, socket) could be manipulated by that owner. This is a hardening check against pre-created or hijacked control directories in shared /tmp.

Source

Thrown at packages/cli/src/utils/detached-run-control.ts:65

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)}`
    );
  }
}

/** A bounded, user-scoped endpoint: Unix socket on POSIX, named pipe on Windows. */

View on GitHub (pinned to 0773b97458)

Solutions

  1. Check ownership: ls -ln /tmp/archon-* and compare the uid with id -u.
  2. Remove the mis-owned directory if no run is active: sudo rm -rf /tmp/archon-<uid>, then re-run as your user.
  3. Avoid mixing sudo and non-sudo invocations of detached Archon runs; use a consistent user.

Example fix

// before
$ ls -ln /tmp | grep archon
drwx------ root root archon-1000
// after
$ sudo rm -rf /tmp/archon-1000
$ archon run ...   # recreated as uid 1000
Defensive patterns

Strategy: try-catch

Validate before calling

import { lstatSync } from 'node:fs';
function ownedByMe(dir: string): boolean {
  try { return lstatSync(dir).uid === process.getuid(); }
  catch { return true; }
}

Try / catch

try {
  const dir = controlDirectory();
} catch (err) {
  if (err instanceof Error && err.message.includes('owned by another user')) {
    console.error('Control dir mis-owned; remove it as its owner and re-run as your user.');
  } else throw err;
}

Prevention

When it happens

Trigger: stat.uid from lstatSync(directory) differs from process.getuid() while resolving a detached-run control path or lock path on a non-Windows platform.

Common situations: Another local user created /tmp/archon-<your-uid> first (spoofing the fixed per-uid name); running Archon under sudo after a first run created the directory as root; a shared container where the directory was created by a different uid mapping.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/2283ea5ddc635087. Report an issue: GitHub.