affaan-m/ECC · error
is invalid at : expected a JSON object
Error message
${label} is invalid at ${filePath}: expected a JSON object What it means
readJsonObject() additionally enforces that the parsed value is a plain JSON object. If the file parses to null, a primitive, or an array, it throws this error stating a JSON object was expected. It guards inventory/state readers against structurally wrong files that are nonetheless valid JSON.
Solutions
- Wrap the file's contents in a JSON object — e.g. change `["agents"]` to `{ "selectedModules": ["agents"] }` matching the expected schema.
- Verify you are pointing at the correct file (the label in the message tells you which document was expected).
- Restore the original object-shaped file from git or regenerate it by rerunning the install flow.
- If generating this file in tooling, ensure you serialize an object, never an array or scalar, at the top level.
Example fix
// before (state.json)
["agents", "skills"]
// after
{ "selectedModules": ["agents", "skills"], "operations": [] } Defensive patterns
Strategy: type-guard
Validate before calling
const value = JSON.parse(fs.readFileSync(statePath, 'utf8'));
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
throw new Error(`${statePath} must contain a top-level JSON object`);
} Type guard
function isJsonObject(v) {
return v !== null && typeof v === 'object' && !Array.isArray(v);
} Try / catch
try {
const state = readJsonObject(statePath, 'Managed Claude install-state');
} catch (err) {
if (err.message.includes('expected a JSON object')) {
console.error(`${statePath} has the wrong top-level type; wrap contents in an object`);
process.exitCode = 1;
} else throw err;
} Prevention
- Always serialize objects (never bare arrays or scalars) when writing state/inventory files.
- Point tooling at the exact expected file paths instead of guessing between similar JSON files.
- Add a schema/type check to any script that generates these files.
- Document the expected top-level shape next to the file-producing code.
When it happens
Trigger: Calling readJsonObject(filePath, label) on a file whose top level is an array (e.g. a bare JSON list of modules), a string/number, or the literal `null`; pointing the reader at a different file that happens to be valid JSON but not an object.
Common situations: Someone 'simplifying' state files to an array; exporting a list from another tool into the state path; an empty-file edge where content like `[]` or `"..."` replaced the object; wrong file passed as the state/inventory path.
Related errors
- Invalid at : expected a JSON object
- Invalid at : expected a JSON object
- Invalid at : expected a JSON object
- Invalid at : expected a JSON object
- Invalid : expected JSON-compatible data
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/c9d15036aedc9175.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/inventory.js:39
|| path.join(homeDir, '.claude');
const projectRoot = options.projectRoot || process.cwd();
return {
homeDir: path.resolve(homeDir),
configDir: path.resolve(configDir),
projectRoot: path.resolve(projectRoot),
};
}
function readJsonObject(filePath, label) {
let value;
try {
value = JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (error) {
throw new Error(`${label} is invalid at ${filePath}: ${error.message}`);
}
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw new Error(`${label} is invalid at ${filePath}: expected a JSON object`);
}
return value;
}
function findManualClaudePlugin(options = {}) {
const { configDir } = resolveClaudePaths(options);
const pluginsDir = path.join(configDir, 'plugins');
const candidates = [
['ecc', '.claude-plugin', 'plugin.json'],
['ecc', 'plugin.json'],
['ecc@ecc', '.claude-plugin', 'plugin.json'],
['ecc@ecc', 'plugin.json'],
['everything-claude-code', '.claude-plugin', 'plugin.json'],
['everything-claude-code', 'plugin.json'],
];
for (const segments of candidates) {
const manifestPath = path.join(pluginsDir, ...segments);View on GitHub (pinned to 8321021c54)