affaan-m/ECC · error · Error

Invalid ${label}: ${error.message}

Error message

Invalid ${label}: ${error.message}

What it means

Thrown by parseJsonLikeValue() in scripts/lib/install-lifecycle.js when the input value is a string that fails JSON.parse. The label identifies the operation field that held the bad string (e.g. 'merge-json.mergePayload').

Source

Thrown at scripts/lib/install-lifecycle.js:162

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 01e15490f0)

Solutions

  1. Inspect the operation field named in the label; reproduce the JSON.parse in isolation.
  2. Switch single quotes to double quotes; remove trailing commas; quote object keys.
  3. If the field is meant to hold free text, change the operation to pass an already-parsed object, not a JSON string.
  4. Validate user input with a JSON schema before constructing the operation.

Example fix

// before
operation.mergePayload = "{ key: 'value' }"; // not JSON

// after
operation.mergePayload = JSON.stringify({ key: 'value' });
// or pass the object directly
operation.mergePayload = { key: 'value' };
Defensive patterns

Strategy: try-catch

Validate before calling

function isJsonString(s) {
  if (typeof s !== 'string') return false;
  try { JSON.parse(s); return true; } catch { return false; }
}
if (typeof value === 'string' && !isJsonString(value)) {
  throw new Error(`${label} is not valid JSON: ${value.slice(0, 120)}`);
}

Type guard

function isParsableJson(s) {
  if (typeof s !== 'string') return false;
  try { JSON.parse(s); return true; } catch { return false; }
}

Try / catch

try {
  return parseJsonLikeValue(value, label);
} catch (err) {
  if (/Invalid .*:/.test(err.message) && typeof value === 'string') {
    throw new Error(`${label} must be valid JSON. Got: ${value.slice(0, 120)}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: parseJsonLikeValue(value, label) where typeof value === 'string' but JSON.parse throws. Called from getOperationJsonPayload / getOperationPreviousJson for fields like mergePayload, managedPayload, payload, value, previousValue, etc.

Common situations: Install operation carries a JSON payload as a malformed string (trailing comma, unquoted key, single quotes); template renderer emitted JS object literal syntax instead of JSON; user-supplied --set value was not valid JSON.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/953cb80de2c18c96. Report an issue: GitHub.