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
- Set identity.targetRoot to a non-empty string (e.g. the absolute path of the installation root) before calling normalized().
- Log or inspect the identity object at the call site to confirm which field is missing or wrongly typed.
- If targetRoot comes from user input or config, validate/coerce it at load time with typeof checks.
- 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
- Always build identities through a factory function that requires both fields.
- Validate config objects at load time, not at query time.
- Type the identity shape in TypeScript with non-optional fields.
- Add a unit test asserting the identity shape before persistence.
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
- a confirmed nonempty coordinate is required
- Invalid )` : ''}
- Unknown state-store schema entity
- Unsafe state-store path
- Unsafe state-store path
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)