affaan-m/ECC · error
Invalid : expected JSON-compatible data
Error message
Invalid ${label}: expected JSON-compatible data What it means
After handling undefined and strings, parseJsonLikeValue accepts null, arrays, plain objects, numbers, and booleans as JSON-compatible values. Any other JavaScript type (function, symbol, bigint, class instance, Date) cannot be safely serialized into the managed settings file, so the library throws. The message is generic; the label used by callers identifies the offending operation field.
Solutions
- Convert the offending value to a plain JSON-compatible structure before passing it (e.g. date.toISOString(), Object.fromEntries(map), plain object literal).
- Ensure operation objects are built from JSON.parse/structuredClone-safe data, not class instances.
- Check the value named by the error label and wrap it with a small normalize step that strips or converts non-JSON types recursively.
- If a Date-like value was intended, store it as an ISO 8601 string.
Example fix
// before
{ kind: 'update-claude-settings', payload: { updatedAt: new Date() } }
// after
{ kind: 'update-claude-settings', payload: { updatedAt: new Date().toISOString() } } Defensive patterns
Strategy: type-guard
Validate before calling
function assertJsonCompatible(value) {
if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return;
if (Array.isArray(value)) return value.forEach(assertJsonCompatible);
if (value && typeof value === 'object' && value.constructor === Object) {
return Object.values(value).forEach(assertJsonCompatible);
}
throw new Error('Non-JSON value in payload');
} Type guard
const isPlainJsonValue = v => v === null || ['string', 'number', 'boolean'].includes(typeof v) || (Array.isArray(v) && v.every(isPlainJsonValue)) || (v !== null && typeof v === 'object' && v.constructor === Object && Object.values(v).every(isPlainJsonValue));
Try / catch
try {
await applyOperation(op);
} catch (err) {
if (/expected JSON-compatible data/.test(err.message)) {
console.error('Convert Dates/Maps/class instances to plain JSON before building the operation.');
} else throw err;
} Prevention
- Round-trip payloads through JSON.parse(JSON.stringify(x)) (or structuredClone after serialization) to strip non-JSON types.
- Serialize Dates as ISO strings at the boundary where operations are built.
- Avoid passing class instances from config loaders directly as operation payloads.
When it happens
Trigger: getOperationJsonPayload or getOperationPreviousJson encounters a non-undefined value at mergePayload/managedPayload/payload/value/expectedValue or previousValue/previousJson/originalValue that is not a string, null, array, plain object, number, or boolean — e.g. a Date, Map, Set, class instance (like a custom config object), or function passed into the operation programmatically.
Common situations: Programmatically building install operations in a script and passing a Date or config-class instance where a plain JSON value is required; state loaded through a deserializer that revives values into class instances instead of plain objects.
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
- Invalid at : expected a JSON object
- Invalid at : expected a JSON object
- Invalid at : expected a JSON object
- Invalid at : expected a JSON object
- Invalid
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/02cc64179100fd4a.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install-lifecycle.js:276
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];
}
}
return null;
}
function getOperationJsonPayload(operation) {
const candidateKeys = ['mergePayload', 'managedPayload', 'payload', 'value', 'expectedValue'];
for (const key of candidateKeys) {View on GitHub (pinned to 8321021c54)