avajs/ava · error · TypeError
${fileForErrorMessage} must export a plain object or factory
Error message
${fileForErrorMessage} must export a plain object or factory function What it means
The default export of an AVA config file must be either a plain object of options or a factory function returning such an object (optionally async, receiving {projectDir}). If it is anything else — a class, array, string, number, etc. — loadConfig throws this TypeError.
Source
Thrown at lib/load-config.js:139
[{config: fileConf, fileForErrorMessage, configFile} = {config: NO_SUCH_FILE, fileForErrorMessage: undefined}, ...conflicting] = results.filter(result => result !== null);
searchDir = path.dirname(searchDir);
} while (fileConf === NO_SUCH_FILE && searchDir !== stopAt);
}
if (conflicting.length > 0) {
throw new Error(`Conflicting configuration in ${fileForErrorMessage} and ${conflicting.map(({fileForErrorMessage}) => fileForErrorMessage).join(' & ')}`);
}
if (fileConf !== NO_SUCH_FILE) {
if (allowConflictWithPackageJson) {
packageConf = {};
} else if (Object.keys(packageConf).length > 0) {
throw new Error(`Conflicting configuration in ${fileForErrorMessage} and package.json`);
}
if (!isPlainObject(fileConf) && typeof fileConf !== 'function') {
throw new TypeError(`${fileForErrorMessage} must export a plain object or factory function`);
}
if (typeof fileConf === 'function') {
fileConf = await fileConf({projectDir});
if (!isPlainObject(fileConf)) {
throw new TypeError(`Factory method exported by ${fileForErrorMessage} must return a plain object`);
}
}
if ('ava' in fileConf) {
throw new Error(`Encountered ’ava’ property in ${fileForErrorMessage}; avoid wrapping the configuration`);
}
}
const config = {
...defaults, nonSemVerExperiments: {}, ...fileConf, ...packageConf, projectDir, configFile,
};View on GitHub (pinned to bbfd946322)
Solutions
- Wrap the configuration in a plain object: `export default {files: [...]}`.
- If exporting an array's contents, spread them: `export default {...options}`.
- Ensure the default export is a function only if it returns a plain object (async allowed).
- Verify the transpiler/bundler output preserves a plain-object default export.
Example fix
// before
export default ['test/**/*.js'];
// after
export default {files: ['test/**/*.js']}; Defensive patterns
Strategy: type-guard
Validate before calling
const mod = await import(configPath);
const c = mod.default;
const isPlainObject = v => v !== null && typeof v === 'object' && !Array.isArray(v) && (v.constructor === Object || v.constructor === undefined);
if (!isPlainObject(c) && typeof c !== 'function') {
throw new TypeError(`${configPath} must default-export a plain object or factory function`);
} Type guard
const isValidAvaConfig = v => (v !== null && typeof v === 'object' && !Array.isArray(v)) || typeof v === 'function';
Try / catch
try {
await run();
} catch (err) {
if (err.message.includes('must export a plain object or factory function')) {
console.error('Default export must be a plain object or a (possibly async) factory returning one');
process.exitCode = 1;
} else throw err;
} Prevention
- Default-export an object literal, not arrays, primitives, or class instances.
- Verify factory configs return plain objects on every path, including async.
- Check transpiler output preserves the plain-object default export.
- Add a config self-test that imports the config file in CI.
When it happens
Trigger: Exporting an array, class instance, or primitive: `export default ['test/**/*.js']` or `export default 'config'`; exporting a non-plain object built with Object.create(null) via unusual constructors.
Common situations: Copy-paste mistakes where the config value was meant to be nested inside an object; default export accidentally set to an import of something else; TypeScript transpilation emitting unexpected wrappers.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- The ’environmentVariables’ configuration must be an object c
- The extensions option must be an array
- Unexpected duplicate extensions in options: ’${[...duplicate
- The ’files’ configuration must be an array containing glob p
- The ’watchMode.ignoreChanges’ configuration must be an array
AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02).
Data as JSON: /api/errors/a799a39b96013dc7.
Report an issue: GitHub.