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

  1. Add `export default {...}` with your AVA configuration object.
  2. Return a factory if you need dynamic config: `export default ({projectDir}) => ({...})`.
  3. Ensure conditional config always yields an object: `process.env.CI ? {...} : {}`.
  4. 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

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


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