{"record":{"id":"c9d15036aedc9175","repo":"affaan-m/ECC","slug":"label-is-invalid-at-filepath-expected-a-jso","errorCode":null,"errorMessage":"${label} is invalid at ${filePath}: expected a JSON object","messagePattern":"(.+?) is invalid at (.+?): expected a JSON object","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/install/inventory.js","lineNumber":39,"sourceCode":"    || path.join(homeDir, '.claude');\n  const projectRoot = options.projectRoot || process.cwd();\n\n  return {\n    homeDir: path.resolve(homeDir),\n    configDir: path.resolve(configDir),\n    projectRoot: path.resolve(projectRoot),\n  };\n}\n\nfunction readJsonObject(filePath, label) {\n  let value;\n  try {\n    value = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n  } catch (error) {\n    throw new Error(`${label} is invalid at ${filePath}: ${error.message}`);\n  }\n  if (!value || typeof value !== 'object' || Array.isArray(value)) {\n    throw new Error(`${label} is invalid at ${filePath}: expected a JSON object`);\n  }\n  return value;\n}\n\nfunction findManualClaudePlugin(options = {}) {\n  const { configDir } = resolveClaudePaths(options);\n  const pluginsDir = path.join(configDir, 'plugins');\n  const candidates = [\n    ['ecc', '.claude-plugin', 'plugin.json'],\n    ['ecc', 'plugin.json'],\n    ['ecc@ecc', '.claude-plugin', 'plugin.json'],\n    ['ecc@ecc', 'plugin.json'],\n    ['everything-claude-code', '.claude-plugin', 'plugin.json'],\n    ['everything-claude-code', 'plugin.json'],\n  ];\n\n  for (const segments of candidates) {\n    const manifestPath = path.join(pluginsDir, ...segments);","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/install/inventory.js#L21-L57","documentation":"Thrown by readJsonObject in scripts/lib/install/inventory.js after JSON.parse succeeds but the value is not a plain object (null, array, or primitive). The inventory reader needs an object so it can read state.target, state.operations, and state.resolution.selectedModules.","triggerScenarios":"An install-state.json whose top level is a JSON array, scalar, or null even though it parses cleanly.","commonSituations":"Another tool overwrote install-state.json with a list; a script wrote [] by accident; a generator emitted null for an empty state.","solutions":["Open install-state.json and confirm it starts with {.","If empty, restore a minimal valid state object or back up and remove the file so ECC reinstalls cleanly.","Confirm no external process is writing to the state file."],"exampleFix":"// before (install-state.json)\n[]\n\n// after\n{\n  \"schemaVersion\": \"ecc.install.v1\",\n  \"target\": {},\n  \"resolution\": { \"selectedModules\": [] },\n  \"operations\": []\n}","handlingStrategy":"type-guard","validationCode":"function preflightStateObject(p) {\n  if (!fs.existsSync(p)) return;\n  const v = JSON.parse(fs.readFileSync(p, 'utf8'));\n  if (!(v !== null && typeof v === 'object' && !Array.isArray(v))) {\n    throw new Error(`${p} top level must be a JSON object`);\n  }\n}\npreflightStateObject(statePath);","typeGuard":"function isJsonObject(v) {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":null,"preventionTips":["Treat install-state.json as opaque; never write to it directly.","Audit external tools that may touch the file to confirm they emit objects.","Use a minimal valid object ({ schemaVersion, target, resolution, operations }) if you must seed one."],"tags":["json-schema","install-state","inventory"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}