affaan-m/ECC · error · Error

Refusing to manage legacy sync path through symlinked…

Error message

Refusing to manage legacy sync path through symlinked ancestor: ${filePath}

What it means

recordLegacySyncPath rejects file paths that have a symlinked ancestor between the file and its trusted root (hasUnsafeManagedAncestor). Managing files through symlinked directories could cause the tool to write to an unexpected location, so it fails closed.

Solutions

  1. Remove the symlink in the ancestor chain and use a real directory (or symlink the file itself, not an ancestor)
  2. Pass the fully resolved real path whose ancestors are actual directories
  3. Use a trusted root that is itself the real (non-symlinked) location of the managed files
  4. Re-run after fixing the directory layout

Example fix

// before
recordLegacySyncPath({ statePath, filePath: '/home/me/.codex/config.toml' }) // ~/.codex -> /dotfiles/codex
// after
// manage the real location, whose ancestors are not symlinks:
recordLegacySyncPath({ statePath, filePath: '/dotfiles/codex/config.toml' });
Defensive patterns

Strategy: validation

Validate before calling

function hasSymlinkAncestor(p, stop) {
  let cur = path.dirname(path.resolve(p));
  const end = path.resolve(stop);
  while (cur !== end && cur !== path.parse(cur).root) {
    if (fs.lstatSync(cur).isSymbolicLink()) return true;
    cur = path.dirname(cur);
  }
  return false;
}

Type guard

const safeToManage = (p, root) => !hasSymlinkAncestor(p, root);

Try / catch

try { recordLegacySyncPath(opts); } catch (e) {
  if (String(e.message).includes('symlinked ancestor')) console.error('Resolve symlinked directories before syncing', opts.filePath);
  else throw e;
}

Prevention

When it happens

Trigger: Calling recordLegacySyncPath with a filePath where some ancestor directory (between filePath and the trusted root) is a symlink — detected by hasUnsafeManagedAncestor during path recording.

Common situations: Codex home or a managed subdirectory is a symlink (e.g. dotfiles managed via symlink farms like GNU Stow); passing /tmp-based symlinked paths; a macOS environment where ~/Library or similar is symlinked.

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/79e23e4fb073ff04. Report an issue: GitHub.

Appendix: source

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

  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;
  for (const entry of [...rollbackPaths].reverse()) {
    const filePath = path.resolve(entry.path);
    const trustedRoot = getTrustedRoot(state, filePath);

View on GitHub (pinned to 8321021c54)