{"record":{"id":"7a2876aedafb57d4","repo":"denoland/deno","slug":"resolve-hook-must-return-shortcircuit-true-or","errorCode":null,"errorMessage":"resolve hook must return { shortCircuit: true } or call nextResolve","messagePattern":"resolve hook must return (.+?) or call nextResolve","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/01_require.js","lineNumber":757,"sourceCode":"        try {\n          const resolved = new URL(spec, currentContext.parentURL).href;\n          return { url: resolved, shortCircuit: true };\n        } catch {\n          return { url: null, shortCircuit: true };\n        }\n      } finally {\n        insideResolveHook = false;\n      }\n    }\n    const hook = resolveHooks[index++];\n    let nextCalled = false;\n    const wrappedNext = (s, c) => {\n      nextCalled = true;\n      return nextResolve(s, c);\n    };\n    const result = hook(spec, currentContext, wrappedNext);\n    if (!nextCalled && !result?.shortCircuit) {\n      throw new TypeError(\n        \"resolve hook must return { shortCircuit: true } or call nextResolve\",\n      );\n    }\n    return result;\n  }\n\n  return nextResolve(specifier, context);\n}\n\nfunction esmResolveHookCallback(specifier, referrer, importAttributes) {\n  const attrs = { __proto__: null };\n  if (importAttributes !== null && typeof importAttributes === \"object\") {\n    for (const key in importAttributes) {\n      attrs[key] = importAttributes[key];\n    }\n  }\n  const context = {\n    parentURL: referrer || undefined,","sourceCodeStart":739,"sourceCodeEnd":775,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/node/polyfills/01_require.js#L739-L775","documentation":"Under Node's module.registerHooks() (synchronous module customization hooks, polyfilled by Deno's CJS loader in ext/node/polyfills/01_require.js), every resolve hook must either delegate by calling nextResolve() or take responsibility by returning an object containing shortCircuit: true. If the hook returns undefined (or anything lacking shortCircuit) and never chained, the runner throws this TypeError because the resolution chain cannot continue.","triggerScenarios":"module.registerHooks({ resolve(spec, ctx, nextResolve) { if (spec.startsWith('virtual:')) return { url: spec, shortCircuit: true }; } }) - the non-virtual path neither returns a shortCircuit result nor calls nextResolve; forgetting `return` in an arrow body; a conditional that only returns on some branches.","commonSituations":"Porting registerHooks or module.register loader code from Node; writing hooks where the default path silently falls off the end; refactoring hooks and dropping the final return nextResolve(...) line.","solutions":["Make every code path either return { url, shortCircuit: true, format } or return nextResolve(spec, context)","Use the ternary shape: return cond ? { url, shortCircuit: true } : nextResolve(spec, context)","Add an explicit `return nextResolve(spec, context);` as the last statement of the hook body"],"exampleFix":"// before\nmodule.registerHooks({\n  resolve(spec, context, nextResolve) {\n    if (spec.startsWith(\"virtual:\")) {\n      return { url: `virtual:${spec}`, shortCircuit: true, format: \"module\" };\n    }\n    // falls through: no return, no nextResolve -> TypeError\n  },\n});\n\n// after\nmodule.registerHooks({\n  resolve(spec, context, nextResolve) {\n    if (spec.startsWith(\"virtual:\")) {\n      return { url: `virtual:${spec}`, shortCircuit: true, format: \"module\" };\n    }\n    return nextResolve(spec, context);\n  },\n});","handlingStrategy":"validation","validationCode":"// Write hooks as total functions: every path either short-circuits or chains.\nconst resolveHook = (spec: string, context: object, nextResolve: Function) =>\n  spec.startsWith(\"virtual:\")\n    ? { url: `virtual:${spec}`, shortCircuit: true, format: \"module\" }\n    : nextResolve(spec, context);\n\nmodule.registerHooks({ resolve: resolveHook });","typeGuard":"function isResolveResult(v: unknown): v is { url: string; shortCircuit?: boolean; format?: string } {\n  return v != null && typeof v === \"object\" && \"url\" in v;\n}","tryCatchPattern":null,"preventionTips":["End every hook body with an explicit `return nextResolve(spec, context);`","Prefer ternary/early-return shapes that make missing-return paths impossible","Cover hooks with unit tests that drive both the custom branch and the fall-through branch"],"tags":["node-compat","modules","hooks","loaders","validation"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}