affaan-m/ECC · error

Invalid install-state

Error message

Invalid install-state${label ? ` (${label})` : ''}: ${formatValidationErrors(result.errors)}

What it means

assertValidInstallState validates an install-state object against the hand-rolled ecc.install.v1 schema (mirroring schemas/install-state.schema.json) and throws listing all validation errors. It runs on create, read, and write, so neither reading a corrupt state file nor writing a malformed state object can succeed silently.

Solutions

  1. Read the formatted validation errors in the message — they name the failing field and reason
  2. Restore the missing/renamed field per schemas/install-state.schema.json (ecc.install.v1)
  3. If the state file is from an older version, delete it and re-run the installer to regenerate it
  4. Fix the code path if your own script built the state object and omitted required fields

Example fix

// before
{ "installedAt": "2026-01-01T00:00:00Z" }
// after — include the schema-required version field
{ "version": "ecc.install.v1", "installedAt": "2026-01-01T00:00:00Z" }
Defensive patterns

Strategy: validation

Validate before calling

// Validate against the published schema before use
const Ajv = require('ajv');
const schema = require('./schemas/install-state.schema.json');
const ajv = new Ajv();
const validate = ajv.compile(schema);
if (!validate(state)) console.error(validate.errors); // fix before calling installer APIs

Type guard

function isInstallState(s) {
  return !!s && typeof s === 'object' && !Array.isArray(s)
    && s.version === 'ecc.install.v1'
    && typeof s.installedAt === 'string';
}

Try / catch

try {
  const state = readInstallState();
} catch (e) {
  if (/^Invalid install-state/.test(e.message)) {
    // recover: delete/regenerate the state file per ecc.install.v1 schema
  } else throw e;
}

Prevention

When it happens

Trigger: createInstallState/readInstallState/writeInstallState receive a state object missing required fields (e.g. version, installedAt), with wrong types, or an unrecognized ecc.install.v1 shape — validateInstallState returns valid:false and the formatted errors are thrown.

Common situations: Hand-editing .claude/install-state.json and dropping or renaming a required field; a plugin/schema version upgrade left an old state file that no longer validates; third-party tooling rewrote the state file with a different structure.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at scripts/lib/install-state.js:277

function formatValidationErrors(errors = []) {
  return errors
    .map(error => `${error.instancePath || '/'} ${error.message}`)
    .join('; ');
}

function validateInstallState(state) {
  const validator = getValidator();
  const valid = validator(state);
  return {
    valid,
    errors: validator.errors || [],
  };
}

function assertValidInstallState(state, label) {
  const result = validateInstallState(state);
  if (!result.valid) {
    throw new Error(`Invalid install-state${label ? ` (${label})` : ''}: ${formatValidationErrors(result.errors)}`);
  }
}

function createInstallState(options) {
  const installedAt = options.installedAt || new Date().toISOString();
  const state = {
    schemaVersion: 'ecc.install.v1',
    installedAt,
    target: {
      id: options.adapter.id,
      target: options.adapter.target || undefined,
      kind: options.adapter.kind || undefined,
      root: options.targetRoot,
      installStatePath: options.installStatePath,
    },
    request: {
      profile: options.request.profile || null,
      modules: Array.isArray(options.request.modules) ? [...options.request.modules] : [],

View on GitHub (pinned to 8321021c54)