affaan-m/ECC · error · Error
Refusing to manage non-regular legacy sync path
Error message
Refusing to manage non-regular legacy sync path: ${filePath} What it means
openRegularFileNoFollow safely opens legacy Codex sync files, refusing anything that is not a plain regular file. When an open fails with ENOENT, it lstats the path: if the path actually resolves to a symlink or non-regular file (a race where it vanished/reappeared, or the open failed for another reason), it throws this error instead of proceeding. It protects against managing or overwriting links and special files.
Solutions
- Replace the symlink/special file at the path with a real regular file (cp --remove-destination the target content to a plain file).
- Re-run the sync/uninstall command after the path is a regular file.
- If you intentionally symlink dotfiles, exclude that path from legacy Codex sync or manage it yourself outside this tool.
- Inspect the path: ls -la ~/.codex/... to confirm what is there before retrying.
Example fix
// before ln -s ~/dotfiles/codex-config.toml ~/.codex/config.toml # sync refuses // after rm ~/.codex/config.toml && cp ~/dotfiles/codex-config.toml ~/.codex/config.toml
Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
const st = fs.lstatSync(targetPath); // throws ENOENT if absent (fine)
if (st.isSymbolicLink() || !st.isFile()) throw new Error(`Path must be a regular file: ${targetPath}`); Type guard
function isRegularFileSync(p) { try { const st = require('fs').lstatSync(p); return st.isFile() && !st.isSymbolicLink(); } catch { return false; } } Try / catch
try { await uninstallLegacyCodexSync(); } catch (e) { if (e.message.startsWith('Refusing to manage non-regular')) { console.error('Replace the symlink/special file with a plain file, then retry'); } else throw e; } Prevention
- Don't symlink files managed by legacy Codex sync (e.g. ~/.codex configs) into dotfile repos
- Run ls -la on target paths when sync unexpectedly fails
- Keep sync targets on plain local filesystems, not sockets/devices
When it happens
Trigger: Running install/rollback/uninstall legacy Codex sync when the target path (e.g. ~/.codex config file) is a symlink to elsewhere, a FIFO/device/directory, or turns into one between the failed open and the lstat check (TOCTOU).
Common situations: Users symlink their dotfiles (e.g. ~/.codex/config.toml -> ~/dotfiles/config.toml) into a dotfiles repo; container images placing sockets or special files at the path; partially deleted sync state.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- gate.variant_invalid
- output artifact must be a regular file
- output bundle contains a symlink
- output bundle root must not be a symlink
- output destination must not be a symlink
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/5b5106894a403620.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/codex-legacy-sync.js:28
const BEGIN_MARKER = '<!-- BEGIN ECC -->';
const END_MARKER = '<!-- END ECC -->';
function getStatePath(codexHome) {
return path.join(codexHome, 'ecc', 'legacy-sync-state.json');
}
function openRegularFileNoFollow(filePath, writable = false) {
const noFollow = fs.constants.O_NOFOLLOW || 0;
const flags = (writable ? fs.constants.O_RDWR : fs.constants.O_RDONLY) | noFollow;
let descriptor;
try {
descriptor = fs.openSync(filePath, flags);
} catch (error) {
if (error.code === 'ENOENT') {
try {
const unresolved = fs.lstatSync(filePath);
if (unresolved.isSymbolicLink() || !unresolved.isFile()) {
throw new Error(`Refusing to manage non-regular legacy sync path: ${filePath}`);
}
} catch (lstatError) {
if (lstatError.code === 'ENOENT') return null;
throw lstatError;
}
throw error;
}
if (error.code === 'ELOOP') {
throw new Error(`Refusing to manage non-regular legacy sync path: ${filePath}`);
}
throw error;
}
const descriptorStat = fs.fstatSync(descriptor, { bigint: true });
let finalPathStat;
try {
finalPathStat = fs.lstatSync(filePath, { bigint: true });
} catch (error) {
fs.closeSync(descriptor);View on GitHub (pinned to 8321021c54)