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

  1. Wrap the configuration in a plain object: `export default {files: [...]}`.
  2. If exporting an array's contents, spread them: `export default {...options}`.
  3. Ensure the default export is a function only if it returns a plain object (async allowed).
  4. 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

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


AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02). Data as JSON: /api/errors/a799a39b96013dc7. Report an issue: GitHub.