affaan-m/ECC · error · Error

Refusing to record a legacy sync path outside trusted roots

Error message

Refusing to record a legacy sync path outside trusted roots: ${filePath}

What it means

recordLegacySyncPath refuses to register a file path in the legacy sync state unless that path resolves under one of the trusted roots recorded in the sync state. This is a safety guard so the tool never records or later mutates files outside directories it has been explicitly allowed to manage.

Solutions

  1. Check that the filePath you pass is inside the Codex home or another trusted root recorded in the state file
  2. Add the parent directory to trustedRoots by starting sync from that root (beginLegacySyncState accumulates trusted roots)
  3. Resolve symlinks in your path (fs.realpathSync) before calling, so it lands inside a trusted root
  4. Verify the state file's trustedRoots array includes the intended directory

Example fix

// before
recordLegacySyncPath({ statePath, filePath: '/some/other/place/config.toml' })
// after
const real = require('fs').realpathSync('/some/other/place/config.toml');
// ensure 'real' is under codexHome or a trusted root, then:
recordLegacySyncPath({ statePath, filePath: real });
Defensive patterns

Strategy: validation

Validate before calling

const filePath = path.resolve(candidate);
const state = readState(statePath);
if (!getTrustedRoot(state, filePath)) throw new Error('path not under trusted roots: ' + filePath);

Type guard

const isUnderRoot = (p, root) => path.resolve(p).startsWith(path.resolve(root) + path.sep);

Try / catch

try { recordLegacySyncPath(opts); } catch (e) {
  if (String(e.message).includes('outside trusted roots')) console.error('Add', path.dirname(opts.filePath), 'to trusted roots first');
  else throw e;
}

Prevention

When it happens

Trigger: Calling recordLegacySyncPath({ statePath, filePath }) where path.resolve(filePath) is not inside any trusted root returned by getTrustedRoot(state, filePath) — trusted roots are seeded from codexHome plus prior state's trustedRoots/installedHooksPath.

Common situations: Passing an absolute path in a different directory tree than the Codex home; a path whose symlink resolution escapes the trusted root; passing a repo file path while only codexHome is trusted.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/4081be85c9d64612. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/codex-legacy-sync.js:279

    paths: [],
    rollbackPaths: [],
  };

  for (const [key, filePath] of [['config', configPath], ['agents', agentsPath]]) {
    if (priorState) break;
    const snapshot = readRegularFileNoFollow(filePath, 'utf8');
    state.before[key] = snapshot ? snapshot.content : null;
  }
  atomicWriteJson(statePath, state);
  return statePath;
}

function recordLegacySyncPath(options) {
  const state = readState(options.statePath);
  const filePath = path.resolve(options.filePath);
  const trustedRoot = getTrustedRoot(state, filePath);
  if (!trustedRoot) {
    throw new Error(`Refusing to record a legacy sync path outside trusted roots: ${filePath}`);
  }
  if (hasUnsafeManagedAncestor(filePath, trustedRoot)) {
    throw new Error(`Refusing to manage legacy sync path through symlinked ancestor: ${filePath}`);
  }
  if (!state.paths.some(entry => entry.path === filePath)) {
    const snapshot = snapshotLegacyPath(filePath);
    state.paths.push(snapshot);
    state.rollbackPaths = [...(state.rollbackPaths || []), { ...snapshot }];
    atomicWriteJson(options.statePath, state);
  }
}

function rollbackLegacyCodexSync(options) {
  const state = readState(options.statePath);
  const restoredPaths = [];
  const retainedPaths = [];

  const rollbackPaths = Array.isArray(state.rollbackPaths) ? state.rollbackPaths : state.paths;

View on GitHub (pinned to 8321021c54)