{"id":"16620671eea75d52","repo":"babel/babel","slug":"expected-config-object-but-found-array","errorCode":null,"errorMessage":"Expected config object but found array","messagePattern":"Expected config object but found array","errorType":"exception","errorClass":"ConfigError","httpStatus":null,"severity":"error","filePath":"packages/babel-core/src/config/files/configuration.ts","lineNumber":179,"sourceCode":"\nconst readConfigJSON5 = makeStaticFileCache((filepath, content): ConfigFile => {\n  let options;\n  try {\n    options = json5.parse(content);\n  } catch (err) {\n    throw new ConfigError(\n      `Error while parsing config - ${err.message}`,\n      filepath,\n    );\n  }\n\n  if (!options) throw new ConfigError(`No config detected`, filepath);\n\n  if (typeof options !== \"object\") {\n    throw new ConfigError(`Config returned typeof ${typeof options}`, filepath);\n  }\n  if (Array.isArray(options)) {\n    throw new ConfigError(`Expected config object but found array`, filepath);\n  }\n\n  delete options.$schema;\n\n  return {\n    filepath,\n    dirname: path.dirname(filepath),\n    options,\n  };\n});\n\nconst readIgnoreConfig = makeStaticFileCache((filepath, content) => {\n  const ignoreDir = path.dirname(filepath);\n  const ignorePatterns = content\n    .split(\"\\n\")\n    .map(line => line.replace(/^#.*$/, \"\").trim())\n    .filter(Boolean);\n","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/babel/babel/blob/06b6eae39da4ce0689fad64e2c48a6375a464208/packages/babel-core/src/config/files/configuration.ts#L161-L197","documentation":"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'.","triggerScenarios":"A .babelrc or babel.config.json file whose top-level content is a JSON array, e.g. [ { \"presets\": [...] }, { \"plugins\": [...] } ] or [\"@babel/preset-env\"].","commonSituations":"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.","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 [ ... ]."],"exampleFix":"// before - throws error 25\n[\n  { \"presets\": [\"@babel/preset-env\"] },\n  { \"plugins\": [\"@babel/plugin-transform-runtime\"] }\n]\n\n// after - use overrides\n{\n  \"overrides\": [\n    { \"presets\": [\"@babel/preset-env\"] },\n    { \"plugins\": [\"@babel/plugin-transform-runtime\"] }\n  ]\n}","handlingStrategy":"type-guard","validationCode":"const parsed = require('json5').parse(require('fs').readFileSync('babel.config.json', 'utf8'));\nif (Array.isArray(parsed)) {\n  throw new Error('babel.config.json must be a single object, not an array - use overrides for multiple configs');\n}","typeGuard":"function isNotArray(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}","tryCatchPattern":"try { babel.loadOptionsSync(); }\ncatch (err) {\n  if (/Expected config object but found array/.test(err.message)) {\n    console.error(err.filename, 'top-level is an array - convert to an object with overrides');\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["config","json","validation","babelrc"],"analyzedSha":"06b6eae39da4ce0689fad64e2c48a6375a464208","analyzedAt":"2026-08-03T20:13:43.465Z","schemaVersion":2}