affaan-m/ECC · error

Failed to load policy from

Error message

Failed to load policy from ${resolvedPath}: ${error.message}

What it means

loadPolicy reads a policy JSON file and throws when the file cannot be read or parsed as JSON, wrapping the underlying fs/JSON error with the resolved path. The library requires a readable, valid JSON policy file to configure labels, review, validation, and branch-model behavior, so unreadable or malformed files are a hard failure.

Solutions

  1. Verify the resolved path in the message exists and is a readable file (ls -l <path>).
  2. Run the path through a JSON validator; remove comments/trailing commas — policy files must be strict JSON.
  3. Pass an absolute path or fix the working directory so the relative path resolves correctly.
  4. Restore the policy file from version control if it was deleted or corrupted.

Example fix

// before
loadPolicy('./policy.jsonc'); // comments not allowed, file missing
// after
loadPolicy('/abs/path/to/policy.json'); // strict JSON, absolute path
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
function policyFileOk(p) {
  if (!fs.existsSync(p) || !fs.statSync(p).isFile()) return false;
  try { JSON.parse(fs.readFileSync(p, 'utf8')); return true; } catch { return false; }
}
if (!policyFileOk(policyPath)) throw new Error(`Policy file missing or invalid JSON: ${policyPath}`);

Type guard

null

Try / catch

let policy;
try {
  policy = loadPolicy(path);
} catch (e) {
  if (e.message.startsWith('Failed to load policy')) {
    console.error(`Check that ${path} exists, is readable, and is strict JSON.`, e.message);
    process.exitCode = 1;
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling loadPolicy (via policy or result paths) with a path that does not exist, lacks read permission, is a directory, or contains invalid JSON (comments, trailing commas, BOM issues).

Common situations: Relative path resolved from the wrong working directory, config file renamed/deleted, team member committing an invalid policy with comments, wrong file extension or path typo in the config flag/env var.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

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

});

function loadPolicy(rootDir = process.cwd(), configPath = null) {
  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 : {};
  const mergedLabels = { ...DEFAULT_LABELS, ...labels };
  if (typeof mergedLabels.epic !== 'string' || !mergedLabels.epic.trim()) {
    throw new Error(`Policy file ${resolvedPath} must define labels.epic as a non-empty string`);
  }
  return {
    ...DEFAULT_POLICY,
    ...parsed,
    labels: mergedLabels,

View on GitHub (pinned to 8321021c54)