affaan-m/ECC · error · Error

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

Error message

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

What it means

Thrown by readJsonObject() after the file parsed successfully but the resulting value is not a plain object (it is null, an array, a primitive, or non-object). The label and path pinpoint which artifact has the wrong top-level shape.

Source

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

      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,
    sourceRelativePath: path.join('scaffolds', 'cursor', 'ecc-agent-data.json'),
    destinationPath: path.join(options.targetRoot, 'ecc-agent-data.json'),
    strategy: 'preserve-relative-path'
  });

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Open the file and confirm the top level is an object literal { ... }.
  2. If the contents are an array, wrap them: { "entries": [...] } or restore the expected schema key.
  3. Cross-check the schema against a known-good sibling manifest in the same directory.

Example fix

// before (manifests/install-components.json)
[
  { "id": "x" },
  { "id": "y" }
]

// after
{
  "components": [
    { "id": "x" },
    { "id": "y" }
  ]
}
Defensive patterns

Strategy: validation

Validate before calling

function isPlainObject(v) { return Boolean(v) && typeof v === 'object' && !Array.isArray(v); }
const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
if (!isPlainObject(parsed)) {
  throw new Error(`${label} at ${filePath} must be a JSON object`);
}

Type guard

function isJsonObject(v) {
  return v !== null && typeof v === 'object' && !Array.isArray(v);
}

Try / catch

try {
  return readJsonObject(filePath, label);
} catch (err) {
  if (/expected a JSON object/.test(err.message)) {
    throw new Error(`${label} schema wrong: top level must be { ... }`);
  }
  throw err;
}

Prevention

When it happens

Trigger: readJsonObject(filePath, label) where parsed is an array [...] or primitive. Typical when a manifest file is accidentally an array of entries instead of { modules: [...] } / { components: [...] }.

Common situations: Tool emits the wrong top-level structure (array vs object); manual edit replaced the wrapper object with a bare list; a scaffold data file was rewritten as a list of records.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/91ddf37dfa22351f. Report an issue: GitHub.