affaan-m/ECC · error · Error

Policy file ${resolvedPath} must contain a JSON object, got

Error message

Policy file ${resolvedPath} must contain a JSON object, got ${Array.isArray(parsed) ? 'array' : typeof parsed}

What it means

Thrown by loadPolicy() after the policy file parses successfully but the top-level JSON value is not an object (it is an array, string, number, boolean, or null). The policy must be a JSON object so its fields (labels, review, validation, branchModel, project) can be merged over DEFAULT_POLICY.

Source

Thrown at scripts/lib/github-coordination/policy.js:69

  const resolvedPath = configPath
    ? path.resolve(configPath)
    : path.join(rootDir, 'config', DEFAULT_CONFIG_FILE);

  if (!fs.existsSync(resolvedPath)) {
    return {
      ...DEFAULT_POLICY,
      sourcePath: null,
    };
  }

  let parsed;
  try {
    parsed = JSON.parse(fs.readFileSync(resolvedPath, 'utf8'));
  } catch (error) {
    throw new Error(`Failed to load policy from ${resolvedPath}: ${error.message}`);
  }
  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
    throw new Error(`Policy file ${resolvedPath} must contain a JSON object, got ${Array.isArray(parsed) ? 'array' : typeof parsed}`);
  }
  const labels = typeof parsed.labels === 'object' && parsed.labels !== null && !Array.isArray(parsed.labels) ? parsed.labels : {};
  const review = typeof parsed.review === 'object' && parsed.review !== null && !Array.isArray(parsed.review) ? parsed.review : {};
  const validation = typeof parsed.validation === 'object' && parsed.validation !== null && !Array.isArray(parsed.validation) ? parsed.validation : {};
  const branchModel = typeof parsed.branchModel === 'object' && parsed.branchModel !== null && !Array.isArray(parsed.branchModel) ? parsed.branchModel : {};
  const project = typeof parsed.project === 'object' && parsed.project !== null && !Array.isArray(parsed.project) ? parsed.project : {};
  const fieldNames = typeof project.fieldNames === 'object' && project.fieldNames !== null && !Array.isArray(project.fieldNames) ? project.fieldNames : {};
  return {
    ...DEFAULT_POLICY,
    ...parsed,
    labels: { ...DEFAULT_LABELS, ...labels },
    review: { ...DEFAULT_POLICY.review, ...review },
    validation: { ...DEFAULT_POLICY.validation, ...validation },
    branchModel: { ...DEFAULT_POLICY.branchModel, ...branchModel },
    project: {
      ...DEFAULT_POLICY.project,
      ...project,
      fieldNames: { ...DEFAULT_POLICY.project.fieldNames, ...fieldNames },

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Wrap the contents in an object: { ...your current JSON... }.
  2. If the file holds a labels array, move it under the labels key as an object map, e.g. { "labels": { "epic": "epic" } }.
  3. Re-validate with: node -e "const v=JSON.parse(require('fs').readFileSync('config/github-native-coordination.json','utf8')); if(typeof v!=='object'||v===null||Array.isArray(v)) throw new Error('top level must be object')".

Example fix

// before (file contents):
["epic", "coordination:available"]
// after:
{
  "labels": {
    "epic": "epic",
    "available": "coordination:available"
  }
}
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(resolvedPath, 'utf8'));
if (!isPlainObject(parsed)) {
  throw new Error(`Policy at ${resolvedPath} must be a JSON object, got ${Array.isArray(parsed) ? 'array' : typeof parsed}`);
}

Type guard

function isPolicyObject(v) {
  if (!v || typeof v !== 'object' || Array.isArray(v)) return false;
  return true;
}

Try / catch

try {
  return loadPolicy(rootDir);
} catch (err) {
  if (/must contain a JSON object/) {
    // surface a friendlier error pointing at the offending file
    throw new Error(`Policy shape invalid: ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: loadPolicy reads a file whose contents are a bare JSON array [...] or a primitive (e.g. "" or 42 or true); the typeof/Array.isArray check at policy.js:68 fails and the message reports 'array' or the actual typeof.

Common situations: A user pastes a list of label overrides as the entire file instead of an object; a tool writes a top-level array; file was auto-generated by a script that serializes an array instead of { labels: [...] }.

Related errors


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