{"record":{"id":"11fd29f9df670828","repo":"affaan-m/ECC","slug":"cannot-merge-ecc-configuration-at-destinationpat","errorCode":null,"errorMessage":"Cannot merge ECC configuration at ${destinationPath}: expected a JSON object.","messagePattern":"Cannot merge ECC configuration at (.+?): expected a JSON object\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/multi-harness-setup.js","lineNumber":197,"sourceCode":"        `Refusing unverified ownership from install-state at ${plan.installStatePath}: `\n        + `content digest does not match ${destinationPath}.`\n      );\n    }\n    destinations.add(canonicalDestination);\n  }\n  return { destinations, stateFingerprint: validatedFingerprint };\n}\n\nfunction assertMergeDestination(destinationPath) {\n  if (!fs.existsSync(destinationPath)) return null;\n  let current;\n  try {\n    current = JSON.parse(fs.readFileSync(destinationPath, 'utf8'));\n  } catch (error) {\n    throw new Error(`Cannot merge ECC configuration into invalid JSON at ${destinationPath}: ${error.message}`);\n  }\n  if (!current || typeof current !== 'object' || Array.isArray(current)) {\n    throw new Error(`Cannot merge ECC configuration at ${destinationPath}: expected a JSON object.`);\n  }\n  return current;\n}\n\nfunction isPlainObject(value) {\n  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction findJsonConflicts(current, patch, prefix = '') {\n  if (!isPlainObject(patch)) return [];\n  return Object.entries(patch).flatMap(([key, patchValue]) => {\n    if (!Object.prototype.hasOwnProperty.call(current, key)) return [];\n    const currentValue = current[key];\n    const field = prefix ? `${prefix}.${key}` : key;\n    if (isPlainObject(currentValue) && isPlainObject(patchValue)) {\n      return findJsonConflicts(currentValue, patchValue, field);\n    }\n    return JSON.stringify(currentValue) === JSON.stringify(patchValue) ? [] : [field];","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/multi-harness-setup.js#L179-L215","documentation":"Thrown by assertMergeDestination when the destination file parses as JSON but is not a JSON object — i.e., it is null, an array, or a non-object primitive. merge-json merges ECC's payload into an object root; merging into an array or scalar is undefined and would destroy the existing structure, so the installer refuses. This is a type guard on the shape of the existing config.","triggerScenarios":"Fires when the parsed `current` is falsy, typeof !== 'object', or Array.isArray(current) for a merge-json destination. Occurs when a settings file that ECC expects to be an object is actually a JSON array (e.g., a TSConfig 'extends' list stored standalone), a bare string/number, or the literal null.","commonSituations":"A file like .eslintignore or a JSON array config living at a path ECC treats as an object merge target; null written by another tool to 'clear' a config; a generated manifest that is an array at the root; mislabeling an operation kind (merge-json) for a destination that is fundamentally not an object.","solutions":["Inspect destinationPath: if it should be an object, rewrite it as {} or a proper object literal and re-run.","If the file legitimately holds an array/scalar, it cannot be a merge-json target — exclude it from the managed profile or change the operation kind.","If the file is null/empty, replace it with {} so ECC can merge into it.","Verify the ECC catalog entry for this destination is correct (kind should be merge-json only for object configs)."],"exampleFix":"// before: destination contains an array\n// file: [\"a\", \"b\"]\nclassifyManagedOperation(op, owned); // throws [290]\n\n// after: make it an object root\n// file: { \"items\": [\"a\", \"b\"] }","handlingStrategy":"type-guard","validationCode":"const fs = require('fs');\nfunction assertMergeDestinationIsObject(destinationPath) {\n  if (!fs.existsSync(destinationPath)) return;\n  const v = JSON.parse(fs.readFileSync(destinationPath, 'utf8'));\n  if (!v || typeof v !== 'object' || Array.isArray(v)) {\n    throw new Error(`Cannot merge into ${destinationPath}: root is ${Array.isArray(v) ? 'array' : typeof v}, expected a JSON object.`);\n  }\n}\nassertMergeDestinationIsObject(operation.destinationPath);","typeGuard":"function isJsonObjectFile(filePath) {\n  if (!require('fs').existsSync(filePath)) return true;\n  const v = JSON.parse(require('fs').readFileSync(filePath, 'utf8'));\n  return Boolean(v) && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  classifyManagedOperation(operation, ownedDestinations);\n} catch (err) {\n  if (/expected a JSON object/.test(err.message)) {\n    throw new Error(`${operation.destinationPath} is not a JSON object; convert it or remove it before merge.`);\n  }\n  throw err;\n}","preventionTips":["Keep merge-target config files as objects at the root, never arrays or scalars.","If a file is naturally an array, do not register it as a merge-json destination.","Replace null/empty config files with {} before install.","Review the ECC catalog entry for the destination kind."],"tags":["merge-json","type-guard","configuration","validation","kimi"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}