{"record":{"id":"3dce563a1ccb6498","repo":"affaan-m/ECC","slug":"invalid-label-at-filepath-expected-a-json-o-3dce56","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-targets/cursor-project.js","lineNumber":32,"sourceCode":"  if (path.basename(sourceRelativeFile).toLowerCase() === 'readme.md') {\n    return null;\n  }\n\n  return fileName.endsWith('.md')\n    ? `${fileName.slice(0, -3)}.mdc`\n    : fileName;\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 createJsonMergeOperation({ moduleId, repoRoot, sourceRelativePath, destinationPath }) {\n  const sourcePath = path.join(repoRoot, sourceRelativePath);\n  if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isFile()) {\n    return null;\n  }\n\n  return createManagedOperation({\n    kind: 'merge-json',\n    moduleId,\n    sourceRelativePath,\n    destinationPath,\n    strategy: 'merge-json',\n    ownership: 'managed',","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/install-targets/cursor-project.js#L14-L50","documentation":"Thrown by readJsonObject() after JSON.parse succeeded but the parsed value is not a plain object — it is an array, a primitive (string/number/boolean), or null. The merge-json strategy requires a JSON object root; anything else cannot be merged into the destination.","triggerScenarios":"A source file contains a JSON array ([...]) or a single primitive (e.g. \"true\") and is referenced by a merge-json operation. Also a file that contains only null.","commonSituations":"A list-style JSON (e.g. a list of allowed tools) was mistakenly referenced as a merge source; an empty file parsed to undefined; the wrong file was wired into the module's paths.","solutions":["Ensure the source file's top-level value is an object ({...}).","If the data is naturally an array, change the operation strategy from merge-json to flat-file copy.","Wrap the array under a key: { \"items\": [...] }.","Point the operation at a different source file that contains an object."],"exampleFix":"// before — source file is an array\n[ \"a\", \"b\" ]\n// after — wrap in an object (if a merge is intended)\n{ \"allowed\": [\"a\", \"b\"] }","handlingStrategy":"type-guard","validationCode":"const value = JSON.parse(fs.readFileSync(filePath, 'utf8'));\nif (!value || typeof value !== 'object' || Array.isArray(value)) {\n  throw new Error(`${filePath} must contain a JSON object, got ${Array.isArray(value) ? 'array' : typeof value}`);\n}","typeGuard":"/** @param {unknown} v */\nfunction isPlainObject(v) {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":null,"preventionTips":["Author merge sources as objects — wrap arrays under a key.","If a source is naturally an array, use a flat-file copy operation, not merge-json."],"tags":["install","cursor","json","validation","merge"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}