musistudio/claude-code-router · warning
Custom router does not export a function: ${routerPath}
Error message
Custom router does not export a function: ${routerPath} What it means
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.
Source
Thrown at packages/core/src/gateway/claude-code-router-plugin.ts:213
}
getRouteDiagnostics(): RouteDiagnostic[] {
return [...this.compiled.diagnostics];
}
private async resolveCustomRoute(request: MutableRequestLike): Promise<string | undefined> {
const routerPath = this.config.CUSTOM_ROUTER_PATH;
if (!routerPath) {
return undefined;
}
try {
const resolvedRouterPath = resolveCustomRouterModule(routerPath);
delete requireFromHere.cache[resolvedRouterPath];
const loaded = requireFromHere(resolvedRouterPath) as unknown;
const customRouter = typeof loaded === "function" ? loaded : readDefaultFunction(loaded);
if (!customRouter) {
request.log.warn(`Custom router does not export a function: ${routerPath}`);
return undefined;
}
const result = await customRouter(request, this.config, { event: this.event });
return normalizeRouteSelector(typeof result === "string" ? result : undefined);
} catch (error) {
request.log.error(`Failed to load custom router "${routerPath}": ${formatError(error)}`);
return undefined;
}
}
}
function resolveCustomRouterModule(routerPath: string): string {
const resolved = requireFromHere.resolve(resolveLocalModulePath(routerPath, "Custom router"));
assertJavaScriptModulePath(resolved, "Custom router");
return resolved;
}
function resolveLocalModulePath(value: string, label: string): string {View on GitHub (pinned to 99f24806c6)
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)
Example fix
// before
// my-router.js
export const router = async (request, config, { event }) => "claude-sonnet-4";
// after
// my-router.js
module.exports = async function router(request, config, { event }) {
return "claude-sonnet-4";
}; Defensive patterns
Strategy: validation
Validate before calling
function validateRouterModule(path) {
const loaded = require(path);
const fn = typeof loaded === "function" ? loaded : loaded?.default;
if (typeof fn !== "function") throw new Error(`Router ${path} must export a function`);
return fn;
} Type guard
const isRouterExport = (m: unknown): m is (req: unknown, cfg: unknown, o: unknown) => Promise<unknown> =>
typeof m === "function" || typeof (m as { default?: unknown })?.default === "function"; Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unable to load @the-next-ai/bot-gateway-sdk. ${errors.join("
- Artifact origin is not the configured CCR gateway.
- Artifact URL does not use the CCR media artifact path.
- No available models. Configure at least one provider with a
- ToolHub resolver could not connect to CCR Gateway at ${readi
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/dc42a5a25a6a0ec2.
Report an issue: GitHub.