{"record":{"id":"eae31c47c1a5393d","repo":"affaan-m/ECC","slug":"missing-merge-payload-for-uninstall-operation-d","errorCode":null,"errorMessage":"Missing merge payload for uninstall: ${operation.destinationPath}","messagePattern":"Missing merge payload for uninstall: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/install-lifecycle.js","lineNumber":742,"sourceCode":"        cleanupTargets: []\n      };\n    }\n\n    const existingDestination = getContainedExistingPath(\n      operation.destinationPath,\n      trustedRoot,\n      'uninstall'\n    );\n    if (!existingDestination) {\n      return {\n        removedPaths: [],\n        cleanupTargets: []\n      };\n    }\n\n    const payload = getOperationJsonPayload(operation);\n    if (payload === undefined) {\n      throw new Error(`Missing merge payload for uninstall: ${operation.destinationPath}`);\n    }\n\n    const currentValue = readJsonNoFollow(\n      getManagedDestination(existingDestination, trustedRoot, 'uninstall').managedPath\n    );\n    const nextValue = deepRemoveJsonSubset(currentValue, payload);\n    if (nextValue === JSON_REMOVE_SENTINEL) {\n      const removedPath = removeContainedPath(\n        operation.destinationPath,\n        trustedRoot,\n        'uninstall',\n        { force: true }\n      );\n      return {\n        removedPaths: removedPath ? [operation.destinationPath] : [],\n        cleanupTargets: removedPath ? [removedPath] : []\n      };\n    }","sourceCodeStart":724,"sourceCodeEnd":760,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/install-lifecycle.js#L724-L760","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the merge-json operation in the install-state file and confirm whether `payload`, `previousContent`, or `previousJson` should be present.","Restore the install-state from a backup or regenerate it by reinstalling over the current target.","If the target file is user-managed (e.g. ~/.claude/settings.json), manually revert the merged keys and then uninstall.","Upgrade the installer package to match the version that recorded the operation."],"exampleFix":"// before: uninstall fails — operation has neither payload nor previousContent\n// after: re-install to repopulate state, then uninstall\n./install.sh --target claude\n./install.sh --target claude --uninstall","handlingStrategy":"validation","validationCode":"function isUninstallableMerge(op) {\n  if (op.kind !== 'merge-json') return true;\n  return getOperationPreviousContent(op) !== null\n      || getOperationPreviousJson(op) !== undefined\n      || getOperationJsonPayload(op) !== undefined;\n}\n// before uninstall: state.operations.every(isUninstallableMerge)","typeGuard":"function canUninstallMergeOperation(op) {\n  return op.kind !== 'merge-json' || isUninstallableMerge(op);\n}","tryCatchPattern":"try {\n  await executeUninstallOperation(op, trustedRoot);\n} catch (err) {\n  if (err.message.startsWith('Missing merge payload for uninstall')) {\n    // reinstall to populate payload/previousContent, then uninstall\n  } else throw err;\n}","preventionTips":["Always uninstall with the same installer version that installed.","Back up merge-target files (settings.json) before uninstall so manual revert is possible.","Do not strip payload/previousContent fields from install-state.","Validate the install-state shape before invoking uninstall."],"tags":["uninstall","install","validation","merge-json"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}