{"record":{"id":"4d6de865d3d835cc","repo":"avajs/ava","slug":"fileforerrormessage-must-have-a-default-export","errorCode":null,"errorMessage":"${fileForErrorMessage} must have a default export","messagePattern":"(.+?) must have a default export","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/load-config.js","lineNumber":16,"sourceCode":"import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport url from 'node:url';\n\nimport {isPlainObject} from 'is-plain-object';\nimport {packageConfig, packageJsonPath} from 'package-config';\n\nconst NO_SUCH_FILE = Symbol('no ava.config.js file');\nconst MISSING_DEFAULT_EXPORT = Symbol('missing default export');\nconst EXPERIMENTS = new Set(['observeRunsFromConfig']);\n\nconst importConfig = async ({configFile, fileForErrorMessage}) => {\n\tconst {default: config = MISSING_DEFAULT_EXPORT} = await import(url.pathToFileURL(configFile));\n\tif (config === MISSING_DEFAULT_EXPORT) {\n\t\tthrow new Error(`${fileForErrorMessage} must have a default export`);\n\t}\n\n\treturn config;\n};\n\nconst loadConfigFile = async ({projectDir, configFile}) => {\n\tconst fileForErrorMessage = path.relative(projectDir, configFile);\n\ttry {\n\t\tawait fs.promises.access(configFile);\n\t\treturn {config: await importConfig({configFile, fileForErrorMessage}), configFile, fileForErrorMessage};\n\t} catch (error) {\n\t\tif (error.code === 'ENOENT') {\n\t\t\treturn null;\n\t\t}\n\n\t\tthrow Object.assign(new Error(`Error loading ${fileForErrorMessage}: ${error.message}`), {cause: error});\n\t}\n};","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/avajs/ava/blob/bbfd946322fdeca2b547a691d947fb4e18c0c67f/lib/load-config.js#L1-L34","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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)."],"exampleFix":"// before\nexport const files = ['test/**/*.js'];\n// after\nexport default {files: ['test/**/*.js']};","handlingStrategy":"type-guard","validationCode":"const mod = await import(configPath);\nif (!('default' in mod) || mod.default === undefined) {\n  throw new TypeError(`${configPath} must have a default export`);\n}","typeGuard":"const hasDefaultExport = mod => mod !== null && typeof mod === 'object' && mod.default !== undefined;","tryCatchPattern":"try {\n  await run();\n} catch (err) {\n  if (err.message.endsWith('must have a default export')) {\n    console.error('Add `export default {...}` to your AVA config file');\n    process.exitCode = 1;\n  } else throw err;\n}","preventionTips":["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 = {...}."],"tags":["configuration","esm","default-export"],"backgroundTag":"missing-default-export","analyzedSha":"bbfd946322fdeca2b547a691d947fb4e18c0c67f","analyzedAt":"2026-09-02T01:24:43.834Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}