affaan-m/ECC · error · Error

Failed to parse at

Error message

Failed to parse ${label} at ${filePath}: ${error.message}

What it means

readJsonObject() wraps JSON.parse(fs.readFileSync(...)) for JSON files used as merge payloads during install (hooks config, MCP config, cursor/kimi project scaffolds). When the file exists but is not parseable JSON, the underlying SyntaxError is rethrown with this message, including the file path and the parser's reason.

Solutions

  1. Reproduce the exact parser error: node -e "JSON.parse(require('fs').readFileSync('<file>','utf8'))" or jq . <file>
  2. Fix the reported offset - remove trailing commas/comments, close unbalanced braces
  3. If the file is repo-managed, restore it: git checkout -- <file>

Example fix

// before (hooks config with trailing comma)
{ "hooks": { "PreToolUse": [] }, }

// after
{ "hooks": { "PreToolUse": [] } }
Defensive patterns

Strategy: validation

Validate before calling

function assertValidJsonFile(filePath) {
  const text = fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, ''); // strip BOM
  JSON.parse(text); // throws a SyntaxError with the exact offset before the installer runs
}

for (const payloadPath of collectMergePayloadFiles()) {
  assertValidJsonFile(payloadPath);
}

Try / catch

try {
  resolveInstallPlan(options);
} catch (error) {
  if (/^Failed to parse .*: /.test(error.message)) {
    // error.message names the payload file and parser reason; fix that file, then re-run
  } else {
    throw error;
  }
}

Prevention

When it happens

Trigger: A merge-json source file containing a trailing comma, unquoted key, JSONC-style comment, or truncated content; a BOM-prefixed file; an empty file handed to JSON.parse.

Common situations: Hand-editing hooks.json or an .mcp.json-style config and leaving a trailing comma; files mangled by git merge conflicts; editors saving comments into .json files.

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


AI-assisted analysis of affaan-m/ECC@06c5e118c4 (2026-08-18). Data as JSON: /api/errors/1b388352e06839b5. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/install-executor.js:211

  operations.push(
    buildCopyFileOperation({
      moduleId: options.moduleId,
      sourcePath,
      sourceRelativePath: options.sourceRelativePath,
      destinationPath: options.destinationPath,
      strategy: options.strategy || 'preserve-relative-path'
    })
  );

  return true;
}

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 addCursorAgentDataScaffoldOperations(operations, options) {
  const scaffoldRoot = path.join(options.sourceRoot, 'scaffolds', 'cursor');
  if (!fs.existsSync(scaffoldRoot)) {
    return;
  }

  addFileCopyOperation(operations, {
    moduleId: options.moduleId,
    sourceRoot: options.sourceRoot,

View on GitHub (pinned to 06c5e118c4)