{"record":{"id":"9de5c7995fc50087","repo":"affaan-m/ECC","slug":"invalid-label-at-filepath-expected-a-json-o-9de5c7","errorCode":null,"errorMessage":"Invalid ${label} at ${filePath}: expected a JSON object","messagePattern":"Invalid (.+?) at (.+?): expected a JSON object","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/install/apply.js","lineNumber":53,"sourceCode":"      mappings.push({\n        sourceRel: operation.sourceRelativePath,\n        destRel: path.relative(plan.targetRoot, operation.destinationPath),\n      });\n    }\n  }\n  return buildInstallIndex(mappings);\n}\n\nfunction readJsonObject(filePath, label) {\n  let parsed;\n  try {\n    parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n  } catch (error) {\n    throw new Error(`Failed to parse ${label} at ${filePath}: ${error.message}`);\n  }\n\n  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n    throw new Error(`Invalid ${label} at ${filePath}: expected a JSON object`);\n  }\n\n  return parsed;\n}\n\nfunction stateWithContentDigests(state) {\n  return {\n    ...state,\n    operations: (state.operations || []).map(operation => {\n      if (\n        !operation.destinationPath\n        || !fs.existsSync(operation.destinationPath)\n        || !fs.statSync(operation.destinationPath).isFile()\n      ) {\n        return { ...operation };\n      }\n      return {\n        ...operation,","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/install/apply.js#L35-L71","documentation":"Thrown by readJsonObject in scripts/lib/install/apply.js after JSON.parse succeeds but the value is not a plain object (null, array, or primitive). The apply pipeline needs an object so it can deepMergeJson (for merge-json) or iterate keys; a non-object top level is refused.","triggerScenarios":"An existing destination .mcp.json / mcp.json that is a JSON array or scalar; a source hooks file whose top level is an array.","commonSituations":"User replaced .mcp.json with []; another tool wrote a bare string; a generator emitted null for an empty config.","solutions":["Open the named file and make the top level a JSON object { ... }.","For empty configs use {} rather than [] or null.","Re-run the install."],"exampleFix":"// before (existing ~/.claude/.mcp.json)\n[]\n\n// after\n{ \"mcpServers\": {} }","handlingStrategy":"type-guard","validationCode":"function preflightJsonObject(filePath) {\n  if (!fs.existsSync(filePath)) return;\n  const v = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n  if (!(v !== null && typeof v === 'object' && !Array.isArray(v))) {\n    throw new Error(`${filePath} top level must be a JSON object`);\n  }\n}\n['.mcp.json', 'mcp.json'].forEach(f => preflightJsonObject(path.join(targetRoot, f)));","typeGuard":"function isJsonObject(v) {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":null,"preventionTips":["Keep the top level of every ECC-managed JSON file as an object.","Use {} for empty configs — never [] or null.","Audit tools that write into .mcp.json to confirm they emit objects."],"tags":["json-schema","install-apply","mcp-config"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}