Yeachan-Heo/oh-my-codex · error · Error
Unsafe Autopilot context directory: resolved path escapes re
Error message
Unsafe Autopilot context directory: resolved path escapes repository root
What it means
Thrown by ensureSafeAutopilotContextDir when the realpath of .omx/context resolves outside the repository root (relative path from root is '', starts with '..', or is absolute — the latter indicating a different filesystem root). Even after passing the symlink checks, the resolved real path must remain within the repo.
Source
Thrown at src/hooks/keyword-detector.ts:377
async function ensureSafeAutopilotContextDir(sourceCwd: string): Promise<string> {
const rootRealPath = await realpath(sourceCwd);
const omxDir = join(sourceCwd, '.omx');
await mkdir(omxDir, { recursive: true });
if ((await lstat(omxDir)).isSymbolicLink()) {
throw new Error('Unsafe Autopilot context directory: .omx is a symbolic link');
}
const contextDir = join(omxDir, 'context');
await mkdir(contextDir, { recursive: true });
if ((await lstat(contextDir)).isSymbolicLink()) {
throw new Error('Unsafe Autopilot context directory: .omx/context is a symbolic link');
}
const contextRealPath = await realpath(contextDir);
const relativeToRoot = relative(rootRealPath, contextRealPath);
if (relativeToRoot === '' || relativeToRoot.startsWith('..') || isAbsolute(relativeToRoot)) {
throw new Error('Unsafe Autopilot context directory: resolved path escapes repository root');
}
return contextDir;
}
async function writeUniqueAutopilotContextSnapshot(
sourceCwd: string,
slug: string,
nowIso: string,
body: string,
): Promise<string> {
const contextDir = await ensureSafeAutopilotContextDir(sourceCwd);
const timestamp = utcCompactTimestamp(nowIso);
for (let attempt = 0; attempt < 100; attempt += 1) {
const suffix = attempt === 0 ? '' : `-${attempt + 1}`;
const filename = `${slug}-${timestamp}${suffix}.md`;
const relativePath = `.omx/context/${filename}`;
const absolutePath = resolve(contextDir, filename);
try {View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Run the hook from the real repository path (resolve symlinks in your cwd: cd $(realpath .)) and avoid symlinked checkouts
- Remove bind mounts/junctions on .omx or .omx/context so the directory physically lives under the repo root
- On Windows, ensure the repo and .omx are on the same drive root and not accessed via a subst drive letter
- If using containers, mount the whole repo rather than just the .omx subdirectory
Example fix
# before cd ~/link-to-repo && run-hook # sourceCwd is a symlink; realpath escapes # after cd ~/work/myrepo && run-hook # real path; context resolves inside root
Defensive patterns
Strategy: validation
Validate before calling
import { realpath, relative } from 'node:fs/promises';
import { isAbsolute } from 'node:path';
async function contextWithinRoot(cwd: string): Promise<boolean> {
const root = await realpath(cwd);
const ctx = await realpath(join(cwd, '.omx', 'context')).catch(() => null);
if (!ctx) return true;
const rel = relative(root, ctx);
return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel);
} Try / catch
try { await ensureAutopilotContextSnapshot(cwd, iso, text); } catch (err) {
if ((err as Error).message.includes('escapes repository root')) {
const realCwd = await realpath(cwd);
return ensureAutopilotContextSnapshot(realCwd, iso, text);
}
throw err;
} Prevention
- Run tooling from the realpath of the checkout, not a symlinked path
- Don't bind-mount or junction .omx to locations outside the repo
- On Windows, avoid subst drives for repos; keep repo and state on one drive root
When it happens
Trigger: .omx or .omx/context being a bind mount (Linux), a mount point, or residing in a repo whose realpath differs from sourceCwd (e.g. sourceCwd itself is a symlink to the actual checkout, making relative(rootRealPath, contextRealPath) escape); context dir on a different drive/root on Windows yielding an absolute relative() result.
Common situations: Checking out the repo through a symlinked path (ln -s ~/work/myrepo ~/link && cd ~/link); Docker bind mounts mapping .omx to a host path; Windows subst/junction drives; CI systems that materialize workspaces via links so realpath lands outside the nominal root.
Related errors
- Unsafe Autopilot context directory: .omx is a symbolic link
- Unsafe Autopilot context directory: .omx/context is a symbol
- invalid auth slot name: use 1-64 letters, numbers, '.', '_'
- agents-init target must stay inside the current working dire
- invalid detached leader parent environment
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/f293d80097376a20.
Report an issue: GitHub.