babel/babel · error · ConfigError

Expected config object but found array

Error message

Expected config object but found array

What it means

readConfigJSON5 rejects a parsed config that is an array. Although Babel's transform API accepts an array of configs in some contexts, a config FILE must export a single options object; an array at the top level is ambiguous and unsupported, so Babel throws 'Expected config object but found array'.

Source

Thrown at packages/babel-core/src/config/files/configuration.ts:179

const readConfigJSON5 = makeStaticFileCache((filepath, content): ConfigFile => {
  let options;
  try {
    options = json5.parse(content);
  } catch (err) {
    throw new ConfigError(
      `Error while parsing config - ${err.message}`,
      filepath,
    );
  }

  if (!options) throw new ConfigError(`No config detected`, filepath);

  if (typeof options !== "object") {
    throw new ConfigError(`Config returned typeof ${typeof options}`, filepath);
  }
  if (Array.isArray(options)) {
    throw new ConfigError(`Expected config object but found array`, filepath);
  }

  delete options.$schema;

  return {
    filepath,
    dirname: path.dirname(filepath),
    options,
  };
});

const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
  const ignoreDir = path.dirname(filepath);
  const ignorePatterns = content
    .split("\n")
    .map(line => line.replace(/^#.*$/, "").trim())
    .filter(Boolean);

View on GitHub (pinned to 06b6eae39d)

Solutions

  1. Replace the top-level array with a single merged config object.
  2. If you need multiple configs, use the 'overrides' array property within a single object: { "overrides": [ {...}, {...} ] }.
  3. Ensure the file root is an object, not [ ... ].

Example fix

// before - throws error 25
[
  { "presets": ["@babel/preset-env"] },
  { "plugins": ["@babel/plugin-transform-runtime"] }
]

// after - use overrides
{
  "overrides": [
    { "presets": ["@babel/preset-env"] },
    { "plugins": ["@babel/plugin-transform-runtime"] }
  ]
}
Defensive patterns

Strategy: type-guard

Validate before calling

const parsed = require('json5').parse(require('fs').readFileSync('babel.config.json', 'utf8'));
if (Array.isArray(parsed)) {
  throw new Error('babel.config.json must be a single object, not an array - use overrides for multiple configs');
}

Type guard

function isNotArray(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

Try / catch

try { babel.loadOptionsSync(); }
catch (err) {
  if (/Expected config object but found array/.test(err.message)) {
    console.error(err.filename, 'top-level is an array - convert to an object with overrides');
  }
  throw err;
}

Prevention

When it happens

Trigger: A .babelrc or babel.config.json file whose top-level content is a JSON array, e.g. [ { "presets": [...] }, { "plugins": [...] } ] or ["@babel/preset-env"].

Common situations: Confusing the file-based config format (single object) with the programmatic transform options (which can be an array in some integrations); merging two configs into an array during a refactor.

Related errors


AI-assisted analysis of babel/babel@06b6eae39d (2026-08-03). Data as JSON: /data/errors/16620671eea75d52.json. Report an issue: GitHub.