affaan-m/ECC · error · Error
Invalid installState identity: targetId must be a non-empty…
Error message
Invalid installState identity: targetId must be a non-empty string
What it means
normalizeInstallStateIdentity validates targetId after confirming the identity object exists. If targetId is absent or not a non-empty string — undefined, null, number, or '' — this field-specific error is thrown. It narrows error 558: the identity object was passed, but its targetId field is invalid.
Solutions
- Ensure targetId is a non-empty string, e.g. { targetId: 'my-target', targetRoot: '/path/to/root' }
- Convert numeric ids with String(id) before calling
- Check for property-name/casing mismatches (target_id vs targetId) and map fields explicitly
- Validate at the boundary: if (typeof id !== 'string' || !id.length) fail early with a clearer message
Example fix
// before
normalizeInstallStateIdentity({ targetRoot: root, targetID: 42 }); // wrong key/type
// after
normalizeInstallStateIdentity({ targetId: String(id), targetRoot: root }); Defensive patterns
Strategy: type-guard
Validate before calling
const { targetId, targetRoot } = identity ?? {};
if (typeof targetId !== 'string' || targetId.length === 0) {
throw new Error(`targetId must be a non-empty string, got ${JSON.stringify(targetId)}`);
}
if (typeof targetRoot !== 'string' || targetRoot.length === 0) {
throw new Error('targetRoot must be a non-empty string');
} Type guard
function hasValidIdentityFields(x) {
return typeof x?.targetId === 'string' && x.targetId.length > 0 &&
typeof x?.targetRoot === 'string' && x.targetRoot.length > 0;
} Try / catch
try {
return installStateQuery(identity);
} catch (err) {
if (err.message.includes('targetId must be a non-empty string')) {
console.error('targetId missing/empty — check upstream record mapping');
return null;
} throw err;
} Prevention
- Map snake_case data fields (target_id) to camelCase explicitly before building identity
- Convert numeric ids with String() before constructing the identity object
- Validate identity objects once at ingestion, not at each query site
- Watch for property-name typos (targetID vs targetId) with a shared constructor helper
When it happens
Trigger: Calling installState APIs with { targetRoot } but no targetId; targetId set to a numeric id from a database row; targetId coming from an empty form field or empty env/config value; property-name typo like targetID or target_id so identity.targetId is undefined.
Common situations: Schema drift where the id field was renamed upstream; serialization that dropped the field; constructing the identity manually from a partial record; casing mismatches between snake_case data and camelCase API.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- Invalid installState identity: expected targetId and…
- -32602
- a claim token is required
- a confirmed nonempty coordinate is required
- a generated candidate cannot claim original-source identity
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/e0667ac2e071c39e.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/state-store/queries.js:359
? []
: installState.modules,
operations: installState.operations === undefined || installState.operations === null
? []
: 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(),
};View on GitHub (pinned to 8321021c54)