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

  1. Sanitize to [A-Za-z0-9._/-], strip leading '/' and collapse '..' segments
  2. Keep the name under 128 characters
  3. 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

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


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