affaan-m/ECC · error · Error
Failed to parse ${label} at ${filePath}: ${error.message}
Error message
Failed to parse ${label} at ${filePath}: ${error.message} What it means
Thrown by readJsonObject in scripts/lib/install/apply.js when JSON.parse fails. This local copy of the helper is used for three labels: 'hooks config' (source hooks.json read in buildResolvedClaudeHooks), 'existing JSON config' (destination .mcp.json / mcp.json being merged into during a merge-json operation), and 'MCP config' (source MCP file on the copy-file-with-filtering path). The original parse error is inlined.
Source
Thrown at scripts/lib/install/apply.js:49
}
const mappings = [];
for (const operation of plan.operations) {
if (operation.kind === 'copy-file' && operation.sourceRelativePath) {
mappings.push({
sourceRel: operation.sourceRelativePath,
destRel: path.relative(plan.targetRoot, operation.destinationPath),
});
}
}
return buildInstallIndex(mappings);
}
function readJsonObject(filePath, label) {
let parsed;
try {
parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (error) {
throw new Error(`Failed to parse ${label} at ${filePath}: ${error.message}`);
}
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new Error(`Invalid ${label} at ${filePath}: expected a JSON object`);
}
return parsed;
}
function stateWithContentDigests(state) {
return {
...state,
operations: (state.operations || []).map(operation => {
if (
!operation.destinationPath
|| !fs.existsSync(operation.destinationPath)
|| !fs.statSync(operation.destinationPath).isFile()
) {View on GitHub (pinned to 01e15490f0)
Solutions
- Read the message — it names the exact label and absolute filePath that failed to parse.
- Run node -e "JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'))" <filePath> to surface the position.
- Fix the JSON syntax error, or back up and recreate the file, then re-run the install.
- Strip any BOM: sed -i '1s/^\xEF\xBB\xBF//' <filePath>.
Example fix
// before (existing ~/.claude/.mcp.json)
{
"mcpServers": {
"x": { "command": "npx", }
}
}
// after
{
"mcpServers": {
"x": { "command": "npx" }
}
} Defensive patterns
Strategy: try-catch
Validate before calling
function preflightJson(filePath) {
let raw;
try { raw = fs.readFileSync(filePath, 'utf8'); } catch (e) { if (e.code !== 'ENOENT') throw e; return; }
try { JSON.parse(raw.replace(/^\uFEFF/, '')); }
catch (e) { throw new Error(`Preflight fail ${filePath}: ${e.message}`); }
}
['.mcp.json', 'mcp.json', 'hooks/hooks.json'].forEach(f => {
preflightJson(path.join(targetRoot, f));
}); Type guard
function isJsonObject(v) {
return v !== null && typeof v === 'object' && !Array.isArray(v);
} Try / catch
try {
applyInstallPlan(plan);
} catch (err) {
if (/Failed to parse .* at /.test(err.message)) {
console.error('Corrupt JSON file — see path in message:', err.message);
}
throw err;
} Prevention
- Lint every JSON file under the target root before running install.
- Back up the existing config before merging.
- Strip BOMs from any file written by Windows editors.
When it happens
Trigger: During applyInstallPlan: an existing destination .mcp.json being merged into is corrupt; the source hooks.json is corrupt; a source MCP file that will be copied is corrupt.
Common situations: User's existing ~/.claude/.mcp.json has a syntax error from a prior manual edit; a partial write left by a crashed previous run; an editor inserted a BOM or trailing comma.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse ${label} at ${filePath}: ${error.message}
- Invalid hooks config at ${hooksSourcePath}: expected "hooks"
- Invalid ${label} at ${filePath}: expected a JSON object
- Path traversal rejected: ${relPath}
- Path traversal rejected: ${relPath}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/84810658853fb2d3.
Report an issue: GitHub.