affaan-m/ECC · error · Error

Invalid installState identity: targetRoot must be a…

Error message

Invalid installState identity: targetRoot must be a non-empty string

What it means

normalizeInstallStateIdentity validates the install-state identity object before it is stored or queried. It requires both targetId and targetRoot to be non-empty strings and throws as soon as targetRoot fails that check. This guards the state store against records keyed by malformed identities.

Solutions

  1. Set identity.targetRoot to a non-empty string (e.g. the absolute path of the installation root) before calling normalized().
  2. Log or inspect the identity object at the call site to confirm which field is missing or wrongly typed.
  3. If targetRoot comes from user input or config, validate/coerce it at load time with typeof checks.
  4. Upgrade any producer of these records that predates the targetRoot field so it always emits it.

Example fix

// before
store.normalized({ targetId: 'ecc' });
// after
store.normalized({ targetId: 'ecc', targetRoot: '/home/user/.claude' });
Defensive patterns

Strategy: validation

Validate before calling

function assertIdentity(identity) {
  if (!identity || typeof identity.targetId !== 'string' || identity.targetId.length === 0) throw new TypeError('targetId must be a non-empty string');
  if (typeof identity.targetRoot !== 'string' || identity.targetRoot.length === 0) throw new TypeError('targetRoot must be a non-empty string');
}

Type guard

const hasTargetRoot = (i) => typeof i?.targetRoot === 'string' && i.targetRoot.length > 0;

Try / catch

try {
  const normalized = store.normalized(identity);
} catch (e) {
  if (String(e.message).includes('targetRoot must be a non-empty string')) {
    console.error('installState identity missing targetRoot:', identity);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling normalized() (or any query passing through it) with identity.targetRoot set to undefined, null, an empty string, a number, or a non-string value while targetId happens to be valid.

Common situations: Constructing an identity object by hand and forgetting targetRoot; reading a partially-populated config file where the root key is missing; deserializing JSON records from an older schema that lacks the field.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at scripts/lib/state-store/queries.js:362

      ? []
      : installState.operations,
    installedAt: installState.installedAt || new Date().toISOString(),
    sourceVersion: installState.sourceVersion ?? null,
  };
}

function normalizeInstallStateIdentity(identity) {
  if (!identity || typeof identity !== 'object') {
    throw new Error('Invalid installState identity: expected targetId and targetRoot');
  }

  const targetId = identity.targetId;
  const targetRoot = identity.targetRoot;
  if (typeof targetId !== 'string' || targetId.length === 0) {
    throw new Error('Invalid installState identity: targetId must be a non-empty string');
  }
  if (typeof targetRoot !== 'string' || targetRoot.length === 0) {
    throw new Error('Invalid installState identity: targetRoot must be a non-empty string');
  }

  return { targetId, targetRoot };
}

function normalizeGovernanceEventInput(governanceEvent) {
  return {
    id: governanceEvent.id,
    sessionId: governanceEvent.sessionId ?? null,
    eventType: governanceEvent.eventType,
    payload: governanceEvent.payload ?? null,
    resolvedAt: governanceEvent.resolvedAt ?? null,
    resolution: governanceEvent.resolution ?? null,
    createdAt: governanceEvent.createdAt || new Date().toISOString(),
  };
}

function normalizeWorkItemInput(workItem) {

View on GitHub (pinned to 8321021c54)