affaan-m/ECC · error · Error

Legacy Codex sync state not found at

Error message

Legacy Codex sync state not found at ${statePath}

What it means

readState loads the legacy Codex sync state file (a JSON snapshot of files the installer manages) via a symlink-safe read. When the state file does not exist at statePath, it throws instead of returning null — unlike its sibling readStateIfPresent, which returns null for a missing file. This is an intentional hard failure: callers using readState expect an install to already be registered.

Solutions

  1. Run the install/registration step (beginLegacySyncState) first so the state file is created before reading it.
  2. If a missing state is a legitimate case, switch the caller to readStateIfPresent(statePath), which returns null instead of throwing.
  3. Verify statePath/codexHome is correct (echo $CODEX_HOME, check the resolved path) — a typo'd path looks identical to a missing install.
  4. If the state file was deleted but files exist, reinstall to regenerate a valid state snapshot rather than hand-crafting the JSON.

Example fix

// before
const state = readState(statePath); // throws if never installed
// after
const state = readStateIfPresent(statePath);
if (!state) {
  // fresh machine: run install flow instead
  beginLegacySyncState({ codexHome });
  return;
}
Defensive patterns

Strategy: fallback

Validate before calling

import fs from 'node:fs';
if (!fs.existsSync(statePath)) {
  // treat as fresh install instead of calling readState
}

Try / catch

let state;
try {
  state = readState(statePath);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Legacy Codex sync state not found')) {
    state = null; // fresh machine: run install flow
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling readState(statePath) (directly or through the exported state accessor) when no legacy sync state file exists at statePath — e.g. before the first beginLegacySyncState was ever run, after the state file was manually deleted, or when pointing at the wrong codexHome / wrong state path.

Common situations: Running an update/rollback command that expects a prior install on a machine where the plugin was never installed; a state file removed by a cleanup script or manual `rm`; CI runners with a fresh home directory; typo'd CODEX_HOME environment variable resolving to a different directory.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

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

        `Legacy sync path changed before removal; preserved replacement at ${quarantinePath}`
      );
    }
    throw new Error(`Legacy sync path changed before removal: ${filePath}`);
  }
  fs.unlinkSync(quarantinePath);
  fs.rmdirSync(quarantineDir);
}

function atomicWriteJson(filePath, value) {
  fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });
  const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
  fs.writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
  fs.renameSync(tempPath, filePath);
}

function readState(statePath) {
  const snapshot = readRegularFileNoFollow(statePath, 'utf8');
  if (!snapshot) throw new Error(`Legacy Codex sync state not found at ${statePath}`);
  return parseState(snapshot.content, statePath);
}

function readStateIfPresent(statePath) {
  const snapshot = readRegularFileNoFollow(statePath, 'utf8');
  return snapshot ? parseState(snapshot.content, statePath) : null;
}

function parseState(content, statePath) {
  const state = JSON.parse(content);
  if (state.schema !== SCHEMA || !Array.isArray(state.paths)) {
    throw new Error(`Invalid legacy Codex sync state at ${statePath}`);
  }
  return state;
}

function hasUnsafeManagedAncestor(filePath, codexHome) {
  const relativePath = path.relative(codexHome, filePath);

View on GitHub (pinned to 8321021c54)