Yeachan-Heo/oh-my-codex · error · Error

auth directory must not be a symlink: ${dir}

Error message

auth directory must not be a symlink: ${dir}

What it means

The second-pass batch proof in requireFrozenWindowTopologySync found a pane that is definitively gone ('gone') while the frozen topology still expects it live. This catches panes that died during the tiny window between the first and second validation passes (or after passing pass one).

Source

Thrown at src/auth/paths.ts:57

}

export function resolveDefaultCodexHome(home = homedir()): string {
  return join(home, ".codex");
}

export function resolveLiveAuthPath(
  cwd = process.cwd(),
  env: NodeJS.ProcessEnv = process.env,
  home = homedir(),
): string {
  const codexHome = resolveCodexHomeForLaunch(cwd, env) || resolveDefaultCodexHome(home);
  return join(codexHome, "auth.json");
}

export async function ensurePrivateDir(dir: string): Promise<void> {
  await mkdir(dir, { recursive: true, mode: AUTH_DIR_MODE });
  const info = await lstat(dir);
  if (info.isSymbolicLink()) throw new Error(`auth directory must not be a symlink: ${dir}`);
  if (!info.isDirectory()) throw new Error(`auth path is not a directory: ${dir}`);
  if (process.platform !== "win32") {
    const { chmod } = await import("fs/promises");
    await chmod(dir, AUTH_DIR_MODE).catch(() => undefined);
  }
}

export async function assertReadableFile(path: string, label: string): Promise<void> {
  try {
    const info = await stat(path);
    if (!info.isFile()) throw new Error(`${label} is not a file: ${path}`);
  } catch (err) {
    if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
      throw new Error(`${label} not found: ${path}`);
    }
    throw err;
  }
}

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Enable remain-on-exit on team panes so exited panes stay until deliberately killed
  2. Fix worker processes that exit prematurely
  3. Retry/rebuild: a lost pane invalidates the frozen topology — recreate the session
  4. Coordinate all pane-killing through the library's own teardown APIs

Example fix

# keep dead panes around so topology checks stay consistent
tmux set-option -t myteam remain-on-exit on
Defensive patterns

Strategy: validation

Validate before calling

runTmuxOk(['set-option', '-t', sessionName, 'remain-on-exit', 'on']);

Try / catch

catch (err) { if (/not proven live/.test(err.message)) { rebuildTeamSession(); } }

Prevention

When it happens

Trigger: A pane exiting or being killed between the first per-pane proof and the final batched proof within a single topology validation call.

Common situations: Worker processes exiting under load, scripted pane kills racing the operation, or remain-on-exit off combined with flaky worker processes.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/2fab566d6aaa0ef9. Report an issue: GitHub.