affaan-m/ECC · error · Error

Invalid install-state (${label}): ${details}

Error message

Invalid install-state (${label}): ${details}

What it means

Before writing a refreshed install-state, assertValidInstallStateForWrite runs validateInstallState (JSON-schema validation) and rejects if any errors are returned. The message lists each AJV-style error (instancePath + message) joined by semicolons. This stops the installer from persisting a state shape it cannot later trust.

Source

Thrown at scripts/lib/install-lifecycle.js:1375

      id: record.adapter.id,
      target: record.adapter.target,
      kind: record.adapter.kind,
      root: record.targetRoot,
      installStatePath: record.installStatePath
    }
  };
}

function assertValidInstallStateForWrite(state, label) {
  const validation = validateInstallState(state);
  if (validation.valid) {
    return;
  }

  const details = validation.errors
    .map(error => `${error.instancePath || '/'} ${error.message}`)
    .join('; ');
  throw new Error(`Invalid install-state (${label}): ${details}`);
}

function writeRefreshedInstallState(record, statePreview) {
  const trustedStatePreview = buildAdapterDerivedStatePreview(statePreview, record);
  assertValidInstallStateForWrite(trustedStatePreview, record.installStatePath);
  return writeContainedFile(
    record.installStatePath,
    formatJson(trustedStatePreview),
    record.targetRoot,
    'repair'
  );
}

function prepareRepairMigration(plan, record) {
  const trustedPlan = {
    ...plan,
    adapter: record.adapter,
    targetRoot: record.targetRoot,

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Read the `details` portion of the message — each entry's instancePath points at the failing field.
  2. Fix the upstream producer of that field (adapter, migration, or prior install) so the value satisfies the schema.
  3. If the state is unrecoverable, uninstall and re-install to regenerate it from scratch.
  4. Report an installer bug if the state was produced by the installer itself (attach the listed instancePath/message).

Example fix

// before: state.target.root missing → '/target must NOT have required property root'
// after: regenerate state
./install.sh --target claude --uninstall
./install.sh --target claude
Defensive patterns

Strategy: validation

Validate before calling

function previewWillValidate(statePreview) {
  const v = validateInstallState(statePreview);
  return v.valid ? null : v.errors.map(e => `${e.instancePath || '/'} ${e.message}`).join('; ');
}
// before persisting refreshed state: assert previewWillValidate(state) === null

Type guard

function isValidInstallState(state) {
  return validateInstallState(state).valid === true;
}

Try / catch

try {
  writeRefreshedInstallState(record, statePreview);
} catch (err) {
  if (err.message.startsWith('Invalid install-state')) {
    // read instancePath details, fix upstream field, regenerate state
  } else throw err;
}

Prevention

When it happens

Trigger: Calling writeRefreshedInstallState (during repair) or any path through assertValidInstallStateForWrite when buildAdapterDerivedStatePreview produces a state that fails the schema — e.g. missing required fields, wrong types for target/operations, or an unknown operation kind after hydration.

Common situations: A bug in adapter derivation drops a required field; a migration path produces an operation not covered by the schema; manual edits to the state that survive initial read but fail revalidation on write; schema upgraded in lockstep with older state data.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/93579e48f993cb27. Report an issue: GitHub.