affaan-m/ECC · error · Error

Cannot merge ECC configuration into invalid JSON at ${destin

Error message

Cannot merge ECC configuration into invalid JSON at ${destinationPath}: ${error.message}

What it means

Thrown by assertMergeDestination (called from classifyManagedOperation for kind:'merge-json') when the existing destination file fails JSON.parse. A merge-json operation can only merge into a valid JSON object, so a syntactically broken JSON file is a hard stop rather than a silent overwrite. The underlying parse error message is appended so the caller can see whether it was trailing commas, BOM, truncation, etc.

Source

Thrown at scripts/lib/multi-harness-setup.js:194

      || currentFingerprint.sha256 !== operation.contentSha256.toLowerCase()
    ) {
      throw new Error(
        `Refusing unverified ownership from install-state at ${plan.installStatePath}: `
        + `content digest does not match ${destinationPath}.`
      );
    }
    destinations.add(canonicalDestination);
  }
  return { destinations, stateFingerprint: validatedFingerprint };
}

function assertMergeDestination(destinationPath) {
  if (!fs.existsSync(destinationPath)) return null;
  let current;
  try {
    current = JSON.parse(fs.readFileSync(destinationPath, 'utf8'));
  } catch (error) {
    throw new Error(`Cannot merge ECC configuration into invalid JSON at ${destinationPath}: ${error.message}`);
  }
  if (!current || typeof current !== 'object' || Array.isArray(current)) {
    throw new Error(`Cannot merge ECC configuration at ${destinationPath}: expected a JSON object.`);
  }
  return current;
}

function isPlainObject(value) {
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}

function findJsonConflicts(current, patch, prefix = '') {
  if (!isPlainObject(patch)) return [];
  return Object.entries(patch).flatMap(([key, patchValue]) => {
    if (!Object.prototype.hasOwnProperty.call(current, key)) return [];
    const currentValue = current[key];
    const field = prefix ? `${prefix}.${key}` : key;
    if (isPlainObject(currentValue) && isPlainObject(patchValue)) {

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Open destinationPath and fix the JSON syntax error shown in error.message (remove comments, trailing commas, conflict markers).
  2. If the file is JSONC by intention, convert it to plain JSON or move the configuration to a file ECC can parse.
  3. Resolve any git merge conflict markers in the file.
  4. If the file is irreparable, back it up, delete it so ECC treats the destination as absent (create), then re-run the preview.

Example fix

// before: tsconfig.json contains a comment -> JSON.parse throws
// file: { "compilerOptions": { /* fix */ "strict": true } }
classifyManagedOperation(op, owned); // throws [289]

// after: valid JSON
// file: { "compilerOptions": { "strict": true } }
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
function assertMergeableJson(destinationPath) {
  if (!fs.existsSync(destinationPath)) return;
  JSON.parse(fs.readFileSync(destinationPath, 'utf8')); // throws on invalid JSON
}
// before classify/apply, for each merge-json destination:
assertMergeableJson(operation.destinationPath);

Type guard

function isParsableJson(filePath) {
  try {
    if (!require('fs').existsSync(filePath)) return true;
    JSON.parse(require('fs').readFileSync(filePath, 'utf8'));
    return true;
  } catch { return false; }
}

Try / catch

try {
  classifyManagedOperation(operation, ownedDestinations);
} catch (err) {
  if (/invalid JSON at/.test(err.message)) {
    // surface the path + underlying parse error to the user, do not auto-overwrite
    throw new Error(`Fix the JSON at ${operation.destinationPath} before ECC can merge into it.`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Fires when fs.readFileSync(destinationPath) succeeds but JSON.parse throws, for an operation with kind 'merge-json'. Common when a merge target (e.g., a settings JSON ECC wants to patch) has been hand-edited with a syntax error, was partially written by a crashed process, has a stray BOM/comment (JSONC) that strict JSON.parse rejects, or was corrupted by a merge conflict.

Common situations: Hand-editing tsconfig.json/.eslintrc/settings.json and leaving a trailing comma or comment; a git merge conflict left conflict markers inside the JSON; an editor saving as JSONC with comments; truncated file from a killed process; wrong encoding (UTF-16 BOM).

Understand the failure class

Related errors


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