affaan-m/ECC · error · Error

Missing merge payload for uninstall: ${operation.destination

Error message

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

What it means

During uninstall of a merge-json operation, the installer first tries previousContent / previousJson to restore a backup; if neither is present it must subtract the recorded payload from the current file via deepRemoveJsonSubset. When getOperationJsonPayload returns undefined here, there is no payload to subtract and the uninstall cannot proceed safely.

Source

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

        cleanupTargets: []
      };
    }

    const existingDestination = getContainedExistingPath(
      operation.destinationPath,
      trustedRoot,
      'uninstall'
    );
    if (!existingDestination) {
      return {
        removedPaths: [],
        cleanupTargets: []
      };
    }

    const payload = getOperationJsonPayload(operation);
    if (payload === undefined) {
      throw new Error(`Missing merge payload for uninstall: ${operation.destinationPath}`);
    }

    const currentValue = readJsonNoFollow(
      getManagedDestination(existingDestination, trustedRoot, 'uninstall').managedPath
    );
    const nextValue = deepRemoveJsonSubset(currentValue, payload);
    if (nextValue === JSON_REMOVE_SENTINEL) {
      const removedPath = removeContainedPath(
        operation.destinationPath,
        trustedRoot,
        'uninstall',
        { force: true }
      );
      return {
        removedPaths: removedPath ? [operation.destinationPath] : [],
        cleanupTargets: removedPath ? [removedPath] : []
      };
    }

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Inspect the merge-json operation in the install-state file and confirm whether `payload`, `previousContent`, or `previousJson` should be present.
  2. Restore the install-state from a backup or regenerate it by reinstalling over the current target.
  3. If the target file is user-managed (e.g. ~/.claude/settings.json), manually revert the merged keys and then uninstall.
  4. Upgrade the installer package to match the version that recorded the operation.

Example fix

// before: uninstall fails — operation has neither payload nor previousContent
// after: re-install to repopulate state, then uninstall
./install.sh --target claude
./install.sh --target claude --uninstall
Defensive patterns

Strategy: validation

Validate before calling

function isUninstallableMerge(op) {
  if (op.kind !== 'merge-json') return true;
  return getOperationPreviousContent(op) !== null
      || getOperationPreviousJson(op) !== undefined
      || getOperationJsonPayload(op) !== undefined;
}
// before uninstall: state.operations.every(isUninstallableMerge)

Type guard

function canUninstallMergeOperation(op) {
  return op.kind !== 'merge-json' || isUninstallableMerge(op);
}

Try / catch

try {
  await executeUninstallOperation(op, trustedRoot);
} catch (err) {
  if (err.message.startsWith('Missing merge payload for uninstall')) {
    // reinstall to populate payload/previousContent, then uninstall
  } else throw err;
}

Prevention

When it happens

Trigger: Uninstall (`./install.sh --uninstall`) of a target whose install-state contains a merge-json operation without a payload and without previousContent/previousJson. Commonly the result of a hand-edited or partially-written state file.

Common situations: State file truncated by a crash mid-write; user manually edited install-state to remove payload fields; version drift where an older installer recorded merge-json without a restorable payload.

Related errors


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