jestjs/jest · error · Error
Unable to load resolver at ${options.resolver}
Error message
Unable to load resolver at ${options.resolver} What it means
Thrown by Resolver.findNodeModuleAsync when the configured custom resolver module loads successfully but neither its `async` nor `sync` property resolves to a usable function at call time. It is a defensive guard inside the async resolution path that protects against a resolver object whose exported hooks are missing or falsy after the looser shape-check in loadResolver passed.
Source
Thrown at packages/jest-resolve/src/resolver.ts:159
}
static async findNodeModuleAsync(
path: string,
options: FindNodeModuleConfig,
): Promise<string | null> {
const resolverModule = loadResolver(options.resolver);
let resolver: ResolverInterface = defaultAsyncResolver;
if (typeof resolverModule === 'function') {
resolver = resolverModule;
} else if (
typeof resolverModule.async === 'function' ||
typeof resolverModule.sync === 'function'
) {
const asyncOrSync = resolverModule.async || resolverModule.sync;
if (asyncOrSync == null) {
throw new Error(`Unable to load resolver at ${options.resolver}`);
}
resolver = asyncOrSync;
}
const paths = options.paths;
try {
const result = await resolver(path, {
basedir: options.basedir,
conditions: options.conditions,
defaultAsyncResolver,
defaultResolver,
extensions: options.extensions,
moduleDirectory: options.moduleDirectory,
paths: paths ? [...(nodePaths || []), ...paths] : nodePaths,
rootDir: options.rootDir,
});View on GitHub (pinned to f49721c78e)
Solutions
- Open the file pointed to by `options.resolver` and confirm it exports either a function or an object with at least one of `sync`/`async` as a function.
- If you only need sync resolution, export the function directly: `module.exports = (path, options) => resolvedPath`.
- If you need both, export `{ sync, async }` where both are functions (or at least `async` is defined for the async path).
- Run `node -e "console.log(require('<resolver-path>'))"` to print the actual export shape the test process sees.
Example fix
// before (resolver.js)
module.exports = { sync: null, async: undefined };
// after
const { defaultResolver, defaultAsyncResolver } = require('jest-resolve/build/defaultResolver');
module.exports = {
sync: (path, options) => defaultResolver(path, options),
async: async (path, options) => defaultAsyncResolver(path, options),
}; Defensive patterns
Strategy: validation
Validate before calling
// Run before configuring Jest, or in a setup script
const fs = require('fs');
function validateResolver(resolverPath) {
const mod = require(resolverPath);
const isFn = typeof mod === 'function';
const hasHook = mod && (typeof mod.sync === 'function' || typeof mod.async === 'function');
if (!isFn && !hasHook) {
throw new Error(`Resolver at ${resolverPath} must export a function or {sync, async}`);
}
return mod;
} Type guard
// TypeScript
import type { SyncResolver, ResolverObject } from 'jest-resolve';
function isResolverExport(m: unknown): m is SyncResolver | ResolverObject {
if (typeof m === 'function') return true;
return typeof m === 'object' && m !== null &&
(typeof (m as any).sync === 'function' || typeof (m as any).async === 'function');
} Prevention
- Validate the resolver export shape in a setup script before tests run.
- Prefer exporting a function directly for sync-only resolvers.
- Keep a smoke test that requires the resolver module and asserts the export shape.
When it happens
Trigger: Setting `resolver` in jest config to a module that exports an object (e.g. `module.exports = { async: null }`) or whose `async`/`sync` properties are non-null but not callable, then running an async module resolution (ESM import or require(esm)). Also reachable if a transpiled/bundled resolver loses its function exports at runtime.
Common situations: Migrating from a sync-only custom resolver to the `{sync, async}` form and forgetting to wire the async hook; pointing `resolver` at a TypeScript source file whose compiled output exports the functions under different names; a resolver package that conditionally exports based on `require.main` or Node version and exports an empty object in the test process.
Related errors
- jest.config.mts requires native TypeScript support. Ensure y
- Cannot find module '${moduleName}' from '${relativePath}'
- Resolver located at ${resolver} does not export anything
- Resolver located at ${resolver} does not export a function o
- `jest.advanceTimersByTimeAsync()` is not available when usin
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/c497f09734c88bf4.json.
Report an issue: GitHub.