{"id":"c497f09734c88bf4","repo":"jestjs/jest","slug":"unable-to-load-resolver-at-options-resolver","errorCode":null,"errorMessage":"Unable to load resolver at ${options.resolver}","messagePattern":"Unable to load resolver at (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-resolve/src/resolver.ts","lineNumber":159,"sourceCode":"  }\n\n  static async findNodeModuleAsync(\n    path: string,\n    options: FindNodeModuleConfig,\n  ): Promise<string | null> {\n    const resolverModule = loadResolver(options.resolver);\n    let resolver: ResolverInterface = defaultAsyncResolver;\n\n    if (typeof resolverModule === 'function') {\n      resolver = resolverModule;\n    } else if (\n      typeof resolverModule.async === 'function' ||\n      typeof resolverModule.sync === 'function'\n    ) {\n      const asyncOrSync = resolverModule.async || resolverModule.sync;\n\n      if (asyncOrSync == null) {\n        throw new Error(`Unable to load resolver at ${options.resolver}`);\n      }\n\n      resolver = asyncOrSync;\n    }\n\n    const paths = options.paths;\n\n    try {\n      const result = await resolver(path, {\n        basedir: options.basedir,\n        conditions: options.conditions,\n        defaultAsyncResolver,\n        defaultResolver,\n        extensions: options.extensions,\n        moduleDirectory: options.moduleDirectory,\n        paths: paths ? [...(nodePaths || []), ...paths] : nodePaths,\n        rootDir: options.rootDir,\n      });","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-resolve/src/resolver.ts#L141-L177","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (resolver.js)\nmodule.exports = { sync: null, async: undefined };\n\n// after\nconst { defaultResolver, defaultAsyncResolver } = require('jest-resolve/build/defaultResolver');\nmodule.exports = {\n  sync: (path, options) => defaultResolver(path, options),\n  async: async (path, options) => defaultAsyncResolver(path, options),\n};","handlingStrategy":"validation","validationCode":"// Run before configuring Jest, or in a setup script\nconst fs = require('fs');\nfunction validateResolver(resolverPath) {\n  const mod = require(resolverPath);\n  const isFn = typeof mod === 'function';\n  const hasHook = mod && (typeof mod.sync === 'function' || typeof mod.async === 'function');\n  if (!isFn && !hasHook) {\n    throw new Error(`Resolver at ${resolverPath} must export a function or {sync, async}`);\n  }\n  return mod;\n}","typeGuard":"// TypeScript\nimport type { SyncResolver, ResolverObject } from 'jest-resolve';\nfunction isResolverExport(m: unknown): m is SyncResolver | ResolverObject {\n  if (typeof m === 'function') return true;\n  return typeof m === 'object' && m !== null &&\n    (typeof (m as any).sync === 'function' || typeof (m as any).async === 'function');\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["resolver","config","esm","async"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}