avajs/ava · error · Error
${fileForErrorMessage} must have a default export
Error message
${fileForErrorMessage} must have a default export What it means
AVA config files must provide their configuration as the module's default export. importConfig awaits the dynamic import of the config file and, if `default` is missing, throws this error naming the file for the error message.
Source
Thrown at lib/load-config.js:16
import fs from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import url from 'node:url';
import {isPlainObject} from 'is-plain-object';
import {packageConfig, packageJsonPath} from 'package-config';
const NO_SUCH_FILE = Symbol('no ava.config.js file');
const MISSING_DEFAULT_EXPORT = Symbol('missing default export');
const EXPERIMENTS = new Set(['observeRunsFromConfig']);
const importConfig = async ({configFile, fileForErrorMessage}) => {
const {default: config = MISSING_DEFAULT_EXPORT} = await import(url.pathToFileURL(configFile));
if (config === MISSING_DEFAULT_EXPORT) {
throw new Error(`${fileForErrorMessage} must have a default export`);
}
return config;
};
const loadConfigFile = async ({projectDir, configFile}) => {
const fileForErrorMessage = path.relative(projectDir, configFile);
try {
await fs.promises.access(configFile);
return {config: await importConfig({configFile, fileForErrorMessage}), configFile, fileForErrorMessage};
} catch (error) {
if (error.code === 'ENOENT') {
return null;
}
throw Object.assign(new Error(`Error loading ${fileForErrorMessage}: ${error.message}`), {cause: error});
}
};View on GitHub (pinned to bbfd946322)
Solutions
- Add `export default {...}` with your AVA configuration object.
- Return a factory if you need dynamic config: `export default ({projectDir}) => ({...})`.
- Ensure conditional config always yields an object: `process.env.CI ? {...} : {}`.
- For CJS files use `module.exports = {...}` (ava treats it as default).
Example fix
// before
export const files = ['test/**/*.js'];
// after
export default {files: ['test/**/*.js']}; Defensive patterns
Strategy: type-guard
Validate before calling
const mod = await import(configPath);
if (!('default' in mod) || mod.default === undefined) {
throw new TypeError(`${configPath} must have a default export`);
} Type guard
const hasDefaultExport = mod => mod !== null && typeof mod === 'object' && mod.default !== undefined;
Try / catch
try {
await run();
} catch (err) {
if (err.message.endsWith('must have a default export')) {
console.error('Add `export default {...}` to your AVA config file');
process.exitCode = 1;
} else throw err;
} Prevention
- Always `export default {...}` in ava.config.js/mjs.
- Avoid named-only exports in AVA config files.
- Ensure conditional config branches always return an object.
- For CJS use module.exports = {...}.
When it happens
Trigger: An ava.config.js/mjs/cjs that only uses named exports (`export const files = ...`), only has side effects, or whose default export is conditionally undefined (e.g. `export default process.env.CI && {...}` evaluating to false).
Common situations: Migrating from old `module.exports` style or AVA <1 config formats; TypeScript config transpiled to CJS with esModuleInterop quirks; a config that returns nothing on some branches.
Related errors
- ${fileForErrorMessage} must export a plain object or factory
- Chalk has already been configured
- The ’environmentVariables’ configuration must be an object c
- The extensions option must be an array
- Unexpected duplicate extensions in options: ’${[...duplicate
AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02).
Data as JSON: /api/errors/4d6de865d3d835cc.
Report an issue: GitHub.