affaan-m/ECC · error
is invalid at
Error message
${label} is invalid at ${filePath}: ${error.message} What it means
readJsonObject() in inventory.js parses a JSON file from disk. If JSON.parse or the read fails, it wraps the underlying error message into this error carrying the label, file path, and parse/read failure reason. It distinguishes malformed/unreadable JSON from JSON that is merely the wrong top-level type.
Solutions
- Fix the JSON syntax at the path shown — run the file through a JSON linter or `node -e "JSON.parse(require('fs').readFileSync(p,'utf8'))"` to see the exact parse error.
- Restore the file from version control or a backup if it was hand-edited or corrupted.
- If the file is unrecoverable generated state, delete it and let the installer recreate it via a fresh install.
- Check file permissions/ownership if the message wraps a read/permission error rather than a parse error.
Example fix
// before (state.json)
{ "selectedModules": ["agents"], } // trailing comma
// after
{ "selectedModules": ["agents"] } Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
function isParseableObject(p) {
try {
JSON.parse(fs.readFileSync(p, 'utf8'));
return true;
} catch {
return false;
}
} Type guard
function isPlainObject(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('is invalid at')) {
console.error(`${err.message} — restore from backup or re-run install`);
process.exitCode = 1;
} else throw err;
} Prevention
- Never hand-edit generated JSON state files with editors that add comments/trailing commas.
- Validate JSON after any manual change with a parser before running installer commands.
- Avoid killing the installer mid-write; use atomic writes or wait for completion.
- Keep state files in backups so corrupted files are cheap to restore.
When it happens
Trigger: Calling readJsonObject(filePath, label) on a file containing invalid JSON (trailing commas, comments, truncation); the file cannot be read (missing file, permission error) — those throw the same wrapped message with the underlying error.message; a partially written state file from an interrupted process.
Common situations: Hand-editing Claude install state or inventory JSON and breaking syntax; a crashed installer leaving a truncated file; the file being replaced by a symlink, empty file, or lockfile artifact; encoding issues (BOM) breaking JSON.parse.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- Cannot merge ECC configuration into invalid JSON at
- ! : invalid meta.json, continuing with defaults ( )
- Failed to parse at
- Failed to parse
- Invalid JSON in at
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/ee156496952b0621.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/inventory.js:36
|| os.homedir();
const configDir = options.configDir
|| process.env.CLAUDE_CONFIG_DIR
|| 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'],
];View on GitHub (pinned to 8321021c54)