affaan-m/ECC · error · Error

Missing merge payload for repair: ${operation.destinationPat

Error message

Missing merge payload for repair: ${operation.destinationPath}

What it means

For a 'merge-json' repair, getOperationJsonPayload must return a defined payload object. If it returns undefined (operation has no `payload`/`json` field), the merge cannot be computed, so the repair is rejected. Guards against writing an uncontrolled merged result from an attacker-controllable install-state.

Source

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

    copyContainedFile(sourcePath, operation.destinationPath, trustedRoot, 'repair');
    return operation.destinationPath;
  }

  if (operation.kind === 'render-template') {
    const renderedContent = getOperationTextContent(operation);
    if (renderedContent === null) {
      throw new Error(`Missing rendered content for repair: ${operation.destinationPath}`);
    }

    writeContainedFile(operation.destinationPath, renderedContent, trustedRoot, 'repair');
    return operation.destinationPath;
  }

  if (operation.kind === 'merge-json') {
    const payload = getOperationJsonPayload(operation);
    if (payload === undefined) {
      throw new Error(`Missing merge payload for repair: ${operation.destinationPath}`);
    }

    const existingDestination = getContainedExistingPath(operation.destinationPath, trustedRoot, 'repair');
    const currentValue = existingDestination
      ? readJsonNoFollow(
        getManagedDestination(existingDestination, trustedRoot, 'repair').managedPath
      )
      : {};
    const mergedValue = deepMergeJson(currentValue, payload);

    writeContainedFile(operation.destinationPath, formatJson(mergedValue), trustedRoot, 'repair');
    return operation.destinationPath;
  }

  if (operation.kind === 'remove') {
    const removedPath = removeContainedPath(
      operation.destinationPath,
      trustedRoot,

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Inspect the operation entry in the install-state file at record.installStatePath and confirm it carries a JSON payload.
  2. Uninstall the target and re-install to regenerate a valid install-state.
  3. If merging into a user-edited config (e.g. settings.json), back up the target file first so re-install can re-apply the merge cleanly.
  4. Upgrade the installer package so the operation schema matches what was recorded.

Example fix

// before: { kind: 'merge-json', destinationPath: '...', /* payload missing */ }
// after:
./install.sh --target claude --uninstall
./install.sh --target claude
Defensive patterns

Strategy: validation

Validate before calling

function hasMergePayload(op) {
  if (op.kind !== 'merge-json') return true;
  return getOperationJsonPayload(op) !== undefined;
}
// before repair: state.operations.every(hasMergePayload)

Type guard

function isMergeableOperation(op) {
  return op.kind !== 'merge-json' || getOperationJsonPayload(op) !== undefined;
}

Try / catch

try {
  await executeRepairOperation(repoRoot, op, trustedRoot);
} catch (err) {
  if (err.message.startsWith('Missing merge payload for repair')) {
    // reinstall to repopulate the payload, then repair
  } else throw err;
}

Prevention

When it happens

Trigger: Repair of a merge-json operation whose install-state entry lacks the payload field, or whose payload was set to null/undefined by a schema drift or hand edit. Triggered inside executeRepairOperation for operation.kind === 'merge-json'.

Common situations: Hand-edited install-state; install-state produced by an older version that stored the payload under a different key; partial write of the state file after a crash.

Related errors


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