jestjs/jest · error · Error

Resolver located at ${resolver} does not export a function o

Error message

Resolver located at ${resolver} does not export a function or an object with "sync" and "async" props

What it means

Thrown inside loadResolver when the resolver module exports a value that is neither a function nor an object exposing a `sync` or `async` property. Jest requires one of these two shapes for a custom resolver and rejects anything else (e.g. a string, number, array, or object without the hooks).

Source

Thrown at packages/jest-resolve/src/resolver.ts:959

  const loadedResolver = require(resolver);

  if (loadedResolver == null) {
    throw new Error(`Resolver located at ${resolver} does not export anything`);
  }

  if (typeof loadedResolver === 'function') {
    return loadedResolver as SyncResolver;
  }

  if (
    typeof loadedResolver === 'object' &&
    (loadedResolver.sync != null || loadedResolver.async != null)
  ) {
    return loadedResolver as ResolverObject;
  }

  throw new Error(
    `Resolver located at ${resolver} does not export a function or an object with "sync" and "async" props`,
  );
}

View on GitHub (pinned to f49721c78e)

Solutions

  1. Export a function directly: `module.exports = function(path, options) { ... }`.
  2. Or export `{ sync, async }` (named exactly those keys) where each is a function.
  3. Verify with `node -e "const r = require('./my-resolver.js'); console.log(typeof r, typeof r.sync, typeof r.async)"` — at least one must be 'function'.

Example fix

// before
module.exports = { resolve: (path, options) => { /* ... */ } };

// after
module.exports = { sync: (path, options) => { /* ... */ } };
Defensive patterns

Strategy: type-guard

Validate before calling

function assertResolverShape(resolverPath) {
  const m = require(resolverPath);
  const ok = typeof m === 'function' ||
    (typeof m === 'object' && m && (typeof m.sync === 'function' || typeof m.async === 'function'));
  if (!ok) throw new Error(`Resolver ${resolverPath} must export a function or {sync, async}`);
  return m;
}

Type guard

type ResolverExport = ((path: string, options: any) => string) | { sync?: Function; async?: Function };
function isResolverExport(m: unknown): m is ResolverExport {
  if (typeof m === 'function') return true;
  if (typeof m !== 'object' || m === null) return false;
  return typeof (m as any).sync === 'function' || typeof (m as any).async === 'function';
}

Prevention

When it happens

Trigger: The `resolver` config value points at a module that exports a plain config object, a string, or an object missing both `sync` and `async` keys. Common when someone mistakes the resolver file for a config file or exports a wrapper object like `{ resolve: fn }`.

Common situations: Copy-pasting a resolver example but naming the export `resolve` instead of `sync`/`async`; exporting a class instance whose prototype methods aren't own enumerable `sync`/`async`; pointing `resolver` at the package root whose `main` is a JSON manifest.

Related errors


AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03). Data as JSON: /data/errors/94da80e25a828d50.json. Report an issue: GitHub.