{"record":{"id":"dc42a5a25a6a0ec2","repo":"musistudio/claude-code-router","slug":"custom-router-does-not-export-a-function-router","errorCode":null,"errorMessage":"Custom router does not export a function: ${routerPath}","messagePattern":"Custom router does not export a function: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/core/src/gateway/claude-code-router-plugin.ts","lineNumber":213,"sourceCode":"  }\n\n  getRouteDiagnostics(): RouteDiagnostic[] {\n    return [...this.compiled.diagnostics];\n  }\n\n  private async resolveCustomRoute(request: MutableRequestLike): Promise<string | undefined> {\n    const routerPath = this.config.CUSTOM_ROUTER_PATH;\n    if (!routerPath) {\n      return undefined;\n    }\n\n    try {\n      const resolvedRouterPath = resolveCustomRouterModule(routerPath);\n      delete requireFromHere.cache[resolvedRouterPath];\n      const loaded = requireFromHere(resolvedRouterPath) as unknown;\n      const customRouter = typeof loaded === \"function\" ? loaded : readDefaultFunction(loaded);\n      if (!customRouter) {\n        request.log.warn(`Custom router does not export a function: ${routerPath}`);\n        return undefined;\n      }\n      const result = await customRouter(request, this.config, { event: this.event });\n      return normalizeRouteSelector(typeof result === \"string\" ? result : undefined);\n    } catch (error) {\n      request.log.error(`Failed to load custom router \"${routerPath}\": ${formatError(error)}`);\n      return undefined;\n    }\n  }\n}\n\nfunction resolveCustomRouterModule(routerPath: string): string {\n  const resolved = requireFromHere.resolve(resolveLocalModulePath(routerPath, \"Custom router\"));\n  assertJavaScriptModulePath(resolved, \"Custom router\");\n  return resolved;\n}\n\nfunction resolveLocalModulePath(value: string, label: string): string {","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/gateway/claude-code-router-plugin.ts#L195-L231","documentation":"The gateway tried to load a custom router module configured for a model route, but the resolved module exports neither a function directly nor a default function. The router hook must be a function accepting (request, config, options) and returning a route selector string. When no function export is found the request falls back to default routing.","triggerScenarios":"Setting a model's router to a module path (e.g. ./my-router.js or a marketplace module) whose file exports an object, constants, or nothing instead of module.exports = async (request, config, opts) => \"model-id\". Also happens when the file's default export is an object rather than a function.","commonSituations":"Writing a custom router with ESM-style named exports (export const route = ...) which CommonJS require() sees as an object; transpiling to a module with only named exports; typos in the file path causing a different module to load; default-exporting a class instance instead of a function.","solutions":["Ensure the router module exports a function directly: module.exports = async (request, config, { event }) => \"model-name\"; or a default function: exports.default = async (...) => ...","If using TypeScript/ESM, add a CommonJS-compatible default export or build to CJS","Verify the configured routerPath resolves to the intended file and the module loads without throwing (a throw produces a different error but can mask export issues)","Test the module in isolation: const m = require('./my-router'); console.log(typeof m, typeof m.default)"],"exampleFix":"// before\n// my-router.js\nexport const router = async (request, config, { event }) => \"claude-sonnet-4\";\n\n// after\n// my-router.js\nmodule.exports = async function router(request, config, { event }) {\n  return \"claude-sonnet-4\";\n};","handlingStrategy":"validation","validationCode":"function validateRouterModule(path) {\n  const loaded = require(path);\n  const fn = typeof loaded === \"function\" ? loaded : loaded?.default;\n  if (typeof fn !== \"function\") throw new Error(`Router ${path} must export a function`);\n  return fn;\n}","typeGuard":"const isRouterExport = (m: unknown): m is (req: unknown, cfg: unknown, o: unknown) => Promise<unknown> =>\n  typeof m === \"function\" || typeof (m as { default?: unknown })?.default === \"function\";","tryCatchPattern":null,"preventionTips":["Add a smoke test that requires each custom router and asserts a function export","Prefer module.exports = fn for CJS builds of custom routers","Run typeof checks at startup rather than discovering per-request"],"tags":["custom-router","module-loading","exports","gateway"],"backgroundTag":"module-missing-export","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}