Yeachan-Heo/oh-my-codex · error · Error
Refusing cancellation because multiple detached run…
Error message
Refusing cancellation because multiple detached run authorities match.
What it means
More than one detached run authority record matched the cancellation target (same cwd/context), which is ambiguous, so the CLI refuses to cancel rather than pick arbitrarily.
Solutions
- Cancel one session at a time by its explicit session id rather than by directory
- Remove the stale/finished active record(s) leaving only the live one
- Check for orphaned records after crashes and prune them
Defensive patterns
Strategy: validation
Validate before calling
const matches = records.filter(r => realpathSync(resolve(r.run_dir)) !== null /* + authority checks */);
if (matches.length > 1) throw new Error('ambiguous: cancel by explicit session id'); Prevention
- Cancel by session id, not by directory
- Prune finished active records
- Avoid launching duplicate detached sessions for one cwd
When it happens
Trigger: Two active records both canonicalize to the same working directory and pass authority validation, producing candidates.length > 1.
Common situations: Launching detached sessions twice from the same repo, or stale active records accumulating after crashes (records not cleaned on exit).
Related errors
- Refusing cancellation because state content changed
- approved_execution_binding_ambiguous
- autopilot.session_id must match the selected writable…
- (cancellation_rollback_failed: ).
- Refusing cancellation because detached run authority is…
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/562c3f8e76854d91.
Report an issue: GitHub.
Appendix: source
Thrown at src/cli/index.ts:8165
throw new Error("run directory escapes the authorized runs root");
}
const stateDir = realpathSync(join(canonicalRunDir, ".omx", "state"));
if (!isCanonicalPathWithin(canonicalRunDir, stateDir)) {
throw new Error("state directory escapes the authorized run directory");
}
const session = JSON.parse(await readFile(join(stateDir, "session.json"), "utf-8")) as Record<string, unknown>;
if (session.session_id !== record.session_id) throw new Error("run session pointer changed");
const sessionDir = realpathSync(join(stateDir, "sessions", record.session_id));
if (!isCanonicalPathWithin(stateDir, sessionDir)) {
throw new Error("session directory escapes the authorized state directory");
}
candidates.push({ sessionDir, sessionId: record.session_id, record });
} catch (err) {
throw new Error(`Refusing cancellation because detached run authority is invalid: ${record.run_dir}.`, { cause: err });
}
}
if (candidates.length > 1) throw new Error("Refusing cancellation because multiple detached run authorities match.");
if (candidates.length === 0) return null;
const [{ sessionDir, sessionId, record }] = candidates;
const refs: ModeStateFileRef[] = [];
const stateFiles = await readdir(sessionDir).catch(() => [] as string[]);
for (const file of stateFiles) {
if (!isModeStateFilename(file)) continue;
const path = join(sessionDir, file);
try {
const fileStat = lstatSync(path);
if (!fileStat.isFile() || fileStat.isSymbolicLink()) {
throw new Error(`Refusing cancellation through non-regular run state target: ${path}.`);
}
const canonicalFile = realpathSync(path);
if (!isCanonicalPathWithin(sessionDir, canonicalFile)) {
throw new Error(`Refusing cancellation outside authorized run session: ${path}.`);
}
refs.push({
mode: file.slice(0, -"-state.json".length),View on GitHub (pinned to 3ad79a8a6f)