Yeachan-Heo/oh-my-codex · error · Error
worktreeName must be a relative safe worktree name
Error message
worktreeName must be a relative safe worktree name
What it means
When starting a Hermes session with a custom worktreeName, the name must be relative and safe: 1-128 chars of [A-Za-z0-9._/-], no '..' segments, and not starting with '/'. Violations throw this error before any process spawn, preventing path traversal or absolute-path worktree targets.
Source
Thrown at src/mcp/hermes-bridge.ts:479
const message = error instanceof Error ? error.message : String(error);
if (message.startsWith("unsupported_session_kind")) return failure("prompt_not_accepted", message);
if (message.startsWith("job_not_input_accepting")) return failure("prompt_not_accepted", message);
if (message.includes("allow_mutation")) return failure("mutation_not_allowed", message);
return failure("invalid_input", message);
}
}
export async function hermesStartSession(
args: Record<string, unknown>,
deps: HermesBridgeDeps = {},
): Promise<HermesBridgeResult<{ pid: number; command: string; args: string[]; workingDirectory: string }>> {
try {
requireMutation(args);
const cwd = resolveWorkingDirectoryForState(normalizeString(args.workingDirectory, "workingDirectory", { required: true }));
const prompt = normalizeString(args.prompt, "prompt", { required: true })!;
const worktreeName = normalizeString(args.worktreeName, "worktreeName");
if (worktreeName && (!/^[A-Za-z0-9._/-]{1,128}$/.test(worktreeName) || worktreeName.includes("..") || worktreeName.startsWith("/"))) {
throw new Error("worktreeName must be a relative safe worktree name");
}
const command = (deps.resolveOmxCliEntryPath ?? resolveOmxCliEntryPath)({ cwd }) ?? "omx";
const launchArgs = ["--tmux", worktreeName ? `--worktree=${worktreeName}` : "--worktree", prompt];
const { TMUX: _tmux, TMUX_PANE: _tmuxPane, ...bridgeEnv } = process.env;
const child = (deps.spawnProcess ?? spawn)(command, launchArgs, {
cwd,
detached: true,
stdio: "ignore",
env: { ...bridgeEnv, OMX_HERMES_MCP_BRIDGE: "1" },
}) as ChildProcess;
child.unref();
if (!child.pid) return failure("command_failed", "OMX session launcher did not report a pid");
return jsonResult({ pid: child.pid, command, args: launchArgs, workingDirectory: cwd });
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
if (message.includes("allow_mutation")) return failure("mutation_not_allowed", message);
return failure("invalid_input", message);
}View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Sanitize to [A-Za-z0-9._/-], strip leading '/' and collapse '..' segments
- Keep the name under 128 characters
- Slugify free-form input before passing it as worktreeName
Example fix
// before
{ worktreeName: "../shared/agent" }
// after
{ worktreeName: "shared-agent" } Defensive patterns
Strategy: validation
Validate before calling
function safeWorktreeName(n: string): string | undefined {
const s = n.replace(/[^A-Za-z0-9._/-]/g,'-').replace(/\.\./g,'').replace(/^\/+/, '').slice(0,128);
return s || undefined;
}
args.worktreeName = safeWorktreeName(rawName); Type guard
function isSafeWorktreeName(n: string): boolean { return /^[A-Za-z0-9._/-]{1,128}$/.test(n) && !n.includes('..') && !n.startsWith('/'); } Try / catch
catch (e) { if ((e as Error).message === 'worktreeName must be a relative safe worktree name') { args.worktreeName = slugify(args.worktreeName); retry; } } Prevention
- Slugify branch/user input before using as worktree names
- Reject '..' and leading '/' at the UI boundary
- Cap names at 128 chars
When it happens
Trigger: Passing worktreeName like '../evil', '/abs/path', 'a..b', names with spaces or >128 chars to hermesStartSession.
Common situations: Deriving worktree names from user input or branch names without sanitization; branch names containing spaces, '..', or leading slash.
Related errors
- ${name} must be non-empty
- Unsafe Autopilot context snapshot path: ${existingSnapshot.p
- ${name} is required
- ${name} must be a string
- mutation_not_allowed
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/8bf0fe571a2764c7.
Report an issue: GitHub.