affaan-m/ECC · error
Invalid
Error message
Invalid ${label}: ${error.message} What it means
parseJsonLikeValue accepts either an already-JSON value or a string it tries to JSON.parse. When a string payload (e.g. operation.mergePayload / payload / previousValue for update-claude-settings operations) is not valid JSON, the original JSON.parse SyntaxError message is wrapped as `Invalid <kind>.<key>: <message>`. The label identifies which operation field failed so the broken state record can be located.
Solutions
- Fix the string payload named by the error label (e.g. 'update-claude-settings.mergePayload') so it is valid JSON — validate with JSON.parse in isolation or a linter.
- If the value can be an object instead of a string, store it as a native JSON object/array rather than a serialized string.
- Regenerate the install state (re-run install) instead of hand-repairing the payload string.
- If the input may be JSON5 or comments, normalize it to strict JSON before handing it to the lifecycle functions.
Example fix
// before (state file)
"mergePayload": "{ 'hooks': { 'SessionStart': [] }, }"
// after
"mergePayload": "{\"hooks\":{\"SessionStart\":[]}}" Defensive patterns
Strategy: validation
Validate before calling
function assertValidJsonString(value, label) {
if (typeof value === 'string') JSON.parse(value); // throws early with a clear location
} Type guard
function isJsonString(value) {
if (typeof value !== 'string') return false;
try { JSON.parse(value); return true; } catch { return false; }
} Try / catch
try {
await applyOperation(op);
} catch (err) {
const m = /^Invalid ([\w.-]+): /.exec(err.message);
if (m) {
console.error(`Field ${m[1]} is not valid JSON; fix the state record and re-run.`);
} else throw err;
} Prevention
- Store payloads as native JSON values instead of serialized strings whenever possible.
- Validate JSON strings with a linter/formatter before writing them into install-state.
- Never paste JS object literals (single quotes, trailing commas, comments) into JSON fields.
When it happens
Trigger: getOperationJsonPayload or getOperationPreviousJson reads a string-typed value from operation fields mergePayload/managedPayload/payload/value/expectedValue or previousValue/previousJson/originalValue, and JSON.parse fails on it — e.g. trailing commas, single quotes, comments, truncated JSON, or JS object-literal syntax stored as a string.
Common situations: Hand-editing install-state JSON payloads and leaving a trailing comma or unquoted key; a template or script serializing settings with JSON5-ish syntax; truncation of a long settings payload; paste of a JS object literal into a JSON string field.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- invalid JSON artifact
- Invalid : expected JSON-compatible data
- a top-level committed transaction is required
- application request must be a JSON object
- bundle values must be finite JSON data
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/953cb80de2c18c96.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install-lifecycle.js:268
function cloneJsonValue(value) {
if (value === undefined) {
return undefined;
}
return JSON.parse(JSON.stringify(value));
}
function parseJsonLikeValue(value, label) {
if (value === undefined) {
return undefined;
}
if (typeof value === 'string') {
try {
return JSON.parse(value);
} catch (error) {
throw new Error(`Invalid ${label}: ${error.message}`);
}
}
if (value === null || Array.isArray(value) || isPlainObject(value) || typeof value === 'number' || typeof value === 'boolean') {
return cloneJsonValue(value);
}
throw new Error(`Invalid ${label}: expected JSON-compatible data`);
}
function getOperationTextContent(operation) {
const candidateKeys = ['renderedContent', 'content', 'managedContent', 'expectedContent', 'templateOutput'];
for (const key of candidateKeys) {
if (typeof operation[key] === 'string') {
return operation[key];
}
}View on GitHub (pinned to 8321021c54)