{"id":"da51638b9d9b8380","repo":"jestjs/jest","slug":"jest-failed-to-load-esm-at-filepath-did-you","errorCode":null,"errorMessage":"Jest: Failed to load ESM at ${filePath} - did you use a default export?","messagePattern":"Jest: Failed to load ESM at (.+?) - did you use a default export\\?","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-util/src/requireOrImportModule.ts","lineNumber":29,"sourceCode":"\nasync function importModule(\n  filePath: string,\n  applyInteropRequireDefault: boolean,\n) {\n  try {\n    const moduleUrl = pathToFileURL(filePath);\n\n    // node `import()` supports URL, but TypeScript doesn't know that\n    const importedModule = await import(\n      /* webpackIgnore: true */ moduleUrl.href\n    );\n\n    if (!applyInteropRequireDefault) {\n      return importedModule;\n    }\n\n    if (!importedModule.default) {\n      throw new Error(\n        `Jest: Failed to load ESM at ${filePath} - did you use a default export?`,\n      );\n    }\n\n    return importedModule.default;\n  } catch (error: any) {\n    if (error.message === 'Not supported') {\n      throw new Error(\n        `Jest: Your version of Node does not support dynamic import - please enable it or use a .cjs file extension for file ${filePath}`,\n      );\n    }\n    throw error;\n  }\n}\n\nexport default async function requireOrImportModule<T>(\n  filePath: string,\n  applyInteropRequireDefault = true,","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-util/src/requireOrImportModule.ts#L11-L47","documentation":"Thrown by `importModule` (requireOrImportModule.ts:28-32) when an ESM module (`.mjs`/`.mts`, or a `.js` that triggered `ERR_REQUIRE_ESM`) is dynamically imported, `applyInteropRequireDefault` is true, but the resulting namespace has no `default` export. Jest's interop layer expects a default export to hand back to callers that requested the CJS-style default.","triggerScenarios":"Loading a module via `requireOrImportModule(path)` (used for config files, snapshot resolvers, transformers, custom runners) where the target module is ESM with only named exports and no `default`.","commonSituations":"An ESM config file (`jest.config.mjs`) that does `export const config = {...}` instead of `export default {...}`; a custom snapshot resolver / transformer written as ESM named exports; switching a CJS config (which had `module.exports =`) to ESM and forgetting to switch to `export default`.","solutions":["Add `export default` to the ESM module: `export default { ... }` instead of `export const ...`.","If loading through an API that passes `applyInteropRequireDefault=false`, named exports are returned as the namespace - use that variant when you control the call site.","For Jest config specifically, use the documented ESM form `export default async () => ({...})`."],"exampleFix":"// before: jest.config.mjs\nexport const config = { testEnvironment: 'node' };\n// after\nexport default { testEnvironment: 'node' };","handlingStrategy":"type-guard","validationCode":"// Check the module namespace before relying on .default\nconst mod = await import(pathToFileURL(filePath).href);\nif (!('default' in mod)) throw new Error(`${filePath} needs a default export`);","typeGuard":"const hasDefaultExport = (m: any): boolean =>\n  m != null && 'default' in m && m.default !== undefined;","tryCatchPattern":null,"preventionTips":["Write ESM Jest config as `export default {...}`.","For resolvers/transformers written as ESM, default-export the implementation.","If only named exports make sense, load via the `applyInteropRequireDefault=false` variant."],"tags":["jest-util","esm","module-loading","user-error"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}