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

Refusing cancellation through non-regular state target ${ref

Error message

Refusing cancellation through non-regular state target ${ref.path}.

What it means

Before touching state files, the cancel command lstats each referenced path and requires it to be a regular file that is not a symbolic link. If the target is a symlink, directory, fifo, or missing/special file, cancellation refuses to proceed. This blocks attacks and accidents where state paths are redirected via links.

Source

Thrown at src/cli/index.ts:8407

        string,
        {
          path: string;
          scope: "root" | "session";
          state: Record<string, unknown>;
          originalContent: string;
          dev: number;
          ino: number;
        }
      >();
      if (refs.length === 0) return loaded;
      const canonicalAuthorityRoot = assertCancellationAuthorityPath(
        authorityRoot === writableScope.stateDir ? baseStateDir : authorityRoot,
        authorityRoot,
      );
      for (const ref of refs) {
        const fileStat = lstatSync(ref.path);
        if (!fileStat.isFile() || fileStat.isSymbolicLink()) {
          throw new Error(`Refusing cancellation through non-regular state target ${ref.path}.`);
        }
        const canonicalPath = realpathSync(ref.path);
        const canonicalParent = realpathSync(dirname(ref.path));
        if (!isCanonicalPathWithin(canonicalAuthorityRoot, canonicalParent, true)
          || !isCanonicalPathWithin(canonicalAuthorityRoot, canonicalPath)) {
          throw new Error(`Refusing cancellation outside authorized state root: ${ref.path}.`);
        }
        const content = await readFile(canonicalPath, "utf-8");
        let parsedState: Record<string, unknown>;
        try {
          const parsed = JSON.parse(content) as unknown;
          if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
            throw new Error("state must be a JSON object");
          }
          parsedState = parsed as Record<string, unknown>;
        } catch (err) {
          logCliOperationFailure(err);
          throw new Error(`Refusing partial cancellation because ${ref.path} is malformed.`, { cause: err });

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Replace the symlink at the referenced path with a real regular file (copy contents, remove link)
  2. Point configuration at the actual state directory instead of linking into it
  3. Restore the state file if it was replaced by a link during a move
  4. Avoid symlinked state paths; use bind mounts or direct paths instead

Example fix

# before
ln -s /shared/state.json ~/.omx/state.json
# after
cp /shared/state.json ~/.omx/state.json
Defensive patterns

Strategy: type-guard

Validate before calling

import { lstatSync } from "node:fs";
function isRegularStateFile(path: string): boolean {
  try {
    const st = lstatSync(path);
    return st.isFile() && !st.isSymbolicLink();
  } catch {
    return false;
  }
}

Type guard

import { Stats } from "node:fs";
function isRegularFile(stat: Stats): boolean {
  return stat.isFile() && !stat.isSymbolicLink();
}

Prevention

When it happens

Trigger: A state file reference resolving to a symlink (e.g. state.json -> /etc/something), a directory, or a deleted/non-regular path. lstatSync is used deliberately so symlinks themselves are detected rather than followed.

Common situations: Users symlinking state directories between machines or into dotfiles repos; backup tools replacing files with links; state dir moved and linked back; containerized setups sharing state via links.

Related errors


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