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
- Replace the top-level array with a single merged config object.
- If you need multiple configs, use the 'overrides' array property within a single object: { "overrides": [ {...}, {...} ] }.
- 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
- Use the `overrides` array property instead of a top-level array.
- Never paste an array as the entire config file content.
- Validate the parsed top-level is an object in CI.
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
- No config detected
- Config returned typeof ${typeof options}
- Error while parsing config - ${err.message}
- ${msg(optLoc)} is not allowed in .babelrc or "extends"ed fil
- You appear to be using an async configuration, which your cu
AI-assisted analysis of babel/babel@06b6eae39d (2026-08-03).
Data as JSON: /data/errors/16620671eea75d52.json.
Report an issue: GitHub.