affaan-m/ECC · error · Error

Legacy Codex sync state requires recovery before reinstall:

Error message

Legacy Codex sync state requires recovery before reinstall: ${statePath}

What it means

beginLegacySyncState() refuses to reinstall when the prior state's status is anything other than 'installed'. The sync flips status to 'applying' while work is in flight, so a non-installed status means a previous apply or rollback was interrupted and the recorded rollbackPaths may be half-applied; the operator must complete recovery before ECC touches the tree again.

Source

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

    }
    const digest = snapshot
      ? crypto.createHash('sha256').update(snapshot.content).digest('hex')
      : null;
    if (digest !== entry.installedSha256) {
      throw new Error(`Refusing to replace modified legacy Codex artifact: ${filePath}`);
    }
  }
}

function beginLegacySyncState(options) {
  const codexHome = path.resolve(options.codexHome);
  const statePath = getStatePath(codexHome);
  const configPath = path.join(codexHome, 'config.toml');
  const agentsPath = path.join(codexHome, 'AGENTS.md');
  const installedHooksPath = options.installedHooksPath ? path.resolve(options.installedHooksPath) : null;
  const priorState = readStateIfPresent(statePath);
  if (priorState && priorState.status !== 'installed') {
    throw new Error(`Legacy Codex sync state requires recovery before reinstall: ${statePath}`);
  }
  if (priorState) assertInstalledStateUnmodified(priorState);
  const trustedRoots = [...new Set([
    codexHome,
    ...(Array.isArray(priorState?.trustedRoots) ? priorState.trustedRoots : []),
    ...(priorState?.installedHooksPath ? [priorState.installedHooksPath] : []),
    ...(installedHooksPath ? [installedHooksPath] : []),
  ].map(rootPath => path.resolve(rootPath)))];
  const state = priorState ? {
    ...priorState,
    status: 'applying',
    updatedAt: new Date().toISOString(),
    backupDir: options.backupDir ? path.resolve(options.backupDir) : priorState.backupDir,
    installedHooksPath,
    trustedRoots,
    rollbackPreviousHooksPath: options.previousHooksPath || null,
    rollbackPaths: priorState.paths.map(entry => snapshotLegacyPath(path.resolve(entry.path))),
    previousInstalledState: priorState,

View on GitHub (pinned to 06c5e118c4)

Solutions

  1. Run the legacy Codex sync rollback/recovery entry point (rollbackLegacyCodexSync restores rollbackPaths and clears the state) before reinstalling
  2. If recovery is unavailable, manually verify managed files are intact, back up and delete the state file, then reinstall fresh
  3. Re-run the original sync to completion if it stopped for a retryable reason (lock, transient error)

Example fix

// before: beginLegacySyncState throws Legacy Codex sync state requires recovery before reinstall
rollbackLegacyCodexSync({ statePath }); // finishes the interrupted work
beginLegacySyncState({ codexHome }); // now proceeds
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
function stateNeedsRecovery(statePath) {
  try {
    const prior = JSON.parse(fs.readFileSync(statePath, 'utf8'));
    return typeof prior.status === 'string' && prior.status !== 'installed';
  } catch { return false; }
}
if (stateNeedsRecovery(statePath)) runRecoveryFirst();

Type guard

const needsRecovery = (s) => s !== null && typeof s === 'object' && s.status !== undefined && s.status !== 'installed';

Try / catch

try { beginLegacySyncState({ codexHome }); }
catch (err) {
  if (/requires recovery before reinstall/.test(err.message)) {
    rollbackLegacyCodexSync({ statePath }).then(() => beginLegacySyncState({ codexHome }));
  } else throw err;
}

Prevention

When it happens

Trigger: A prior sync crashed or was Ctrl-C'd between writing status 'applying' and completing; an earlier rollback itself failed leaving a non-installed status; the next beginLegacySyncState() call throws immediately on readStateIfPresent().

Common situations: CI timeout killing the install mid-run; terminal closed or machine slept during apply; a rollback that hit a filesystem error and aborted.

Related errors


AI-assisted analysis of affaan-m/ECC@06c5e118c4 (2026-08-18). Data as JSON: /api/errors/fcf13dd9cb248c2f. Report an issue: GitHub.