affaan-m/ECC · error

Invalid at : expected a JSON object

Error message

Invalid ${label} at ${filePath}: expected a JSON object

What it means

readJsonObject parses a JSON file and requires the result to be a non-null, non-array plain object, because installer config files (like .mcp.json or settings JSON) must be key/value maps to merge safely. Nulls, arrays, and scalars are rejected with a message naming the file's label and path. A parse failure itself throws a separate wrapped error; this one is purely about the parsed shape.

Solutions

  1. Edit the file so its top level is a JSON object: wrap contents in { } and use key/value pairs.
  2. If the file is an empty array, replace it with {}.
  3. Validate with JSON.parse plus a typeof check before handing the path to the installer.
  4. Check which tool rewrote the file and fix its serialization to emit an object.

Example fix

// before: .mcp.json
[]
// after
{
  "mcpServers": {}
}
Defensive patterns

Strategy: validation

Validate before calling

const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
  throw new Error(`${filePath} must contain a top-level JSON object`);
}

Type guard

const isJsonObject = (v) => Boolean(v) && typeof v === 'object' && !Array.isArray(v);

Try / catch

try {
  const cfg = readJsonObject(p, 'MCP config');
} catch (e) {
  if (e.message.includes('expected a JSON object')) {
    console.error(`${p}: rewrite the file with a top-level { } object.`);
  }
  throw e;
}

Prevention

When it happens

Trigger: readJsonObject(filePath, label) reading a file whose top-level JSON is an array ('[...]'), a string/number/boolean literal, or literal 'null' — e.g. a settings file saved as '[]' or a config overwritten with '"text"'.

Common situations: A .mcp.json or settings file that was reset to an empty array; a user replacing an object config with a list of servers; a script serializing an array where an object map was expected; hand-edited JSON losing its root braces.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/9de5c7995fc50087. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/install/apply.js:84

        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) {
    const wrappedError = new Error(`Failed to parse ${label} at ${filePath}: ${error.message}`);
    wrappedError.code = error.code;
    throw wrappedError;
  }

  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
    throw new Error(`Invalid ${label} at ${filePath}: expected a JSON object`);
  }

  return parsed;
}

function readOptionalJsonObject(filePath, label) {
  try {
    return readJsonObject(filePath, label);
  } catch (error) {
    if (error.code === 'ENOENT') {
      return {};
    }
    throw error;
  }
}

function readInstalledFileNoFollow(plan, operation) {
  assertSafeInstallOperation(plan, operation);

View on GitHub (pinned to 8321021c54)