affaan-m/ECC · error

Failed to parse

Error message

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

What it means

parseSettings wraps JSON.parse of raw Claude settings text and rethrows any SyntaxError with a labeled message identifying which settings file failed to parse. The original parse error is preserved as the `cause` for diagnostics. This guards callers (readSettings, readSettingsSnapshot, runTests) from opaque JSON syntax errors with no file context.

Solutions

  1. Open the settings file and fix the JSON syntax; the `cause` property and error message list the exact parse position.
  2. Validate the file with `node -e "JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'))" <path>` before rerunning.
  3. If hand-edits keep breaking, restore the file from version control or let the installer regenerate it.
  4. If the file is JSONC (with comments), strip comments before storing as settings.json.

Example fix

// before (settings.json)
{
  "hooks": {...},
}
// after (remove trailing comma)
{
  "hooks": {...}
}
Defensive patterns

Strategy: try-catch

Validate before calling

const raw = fs.readFileSync(settingsPath, 'utf8').replace(/^\uFEFF/, '');
try { JSON.parse(raw); } catch (e) { throw new Error(`${settingsPath} is not valid JSON: ${e.message}`); }

Type guard

function isParseableJson(text) { try { JSON.parse(text); return true; } catch { return false; } }

Try / catch

try {
  const settings = readSettings(path);
} catch (error) {
  if (error.message.startsWith('Failed to parse')) {
    console.error(`Fix JSON in ${path}:`, error.cause?.message);
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling readSettings(path) or readSettingsSnapshot(path) when the file at settingsPath contains malformed JSON (trailing commas, truncated file, BOM, comments in JSONC format), or passing a non-JSON string directly to parseSettings.

Common situations: A user hand-edited ~/.claude/settings.json and left a trailing comma or comment; an interrupted write left the file truncated; the settings file was saved as JSONC by an editor expecting comments.

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@8321021c54 (2026-09-16). Data as JSON: /api/errors/262c7447c3fdf5d6. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/install/claude-settings.js:315

function materializeManagedHooks(hooksConfig, targetRoot) {
  if (!isJsonObject(hooksConfig) || !isJsonObject(hooksConfig.hooks)) {
    throw new Error('Invalid hooks config: expected a JSON object with a hooks object');
  }
  if (!isNonEmptyString(targetRoot)) {
    throw new Error('Invalid Claude target root: expected a non-empty string');
  }
  return validateManagedHooks(resolveManagedHookCommands(
    replacePluginRootPlaceholders(hooksConfig.hooks, targetRoot),
    targetRoot
  ));
}

function parseSettings(rawSettings, label = 'Claude settings') {
  let settings;
  try {
    settings = JSON.parse(rawSettings);
  } catch (error) {
    throw new Error(`Failed to parse ${label}: ${error.message}`, { cause: error });
  }
  return validateSettings(settings, label);
}

function readSettings(settingsPath, fileSystem = fs) {
  const reader = fileSystem && fileSystem.fs ? fileSystem.fs : fileSystem;
  let rawSettings;
  try {
    rawSettings = reader.readFileSync(settingsPath, 'utf8');
  } catch (error) {
    if (error && error.code === 'ENOENT') {
      return {};
    }
    throw error;
  }
  return parseSettings(rawSettings, `Claude settings at ${settingsPath}`);
}

View on GitHub (pinned to 8321021c54)