musistudio/claude-code-router · error
[plugin:${route.pluginId}] Gateway route ${route.id} failed:
Error message
[plugin:${route.pluginId}] Gateway route ${route.id} failed: ${formatError(error)} What it means
Warned by GatewayPluginService.handleGatewayRoute when a plugin-registered HTTP route handler throws. Unlike transforms, this is user-facing: if headers are not sent yet the client receives a 500 JSON error containing the formatted message; otherwise the response socket is destroyed with the error.
Source
Thrown at packages/core/src/plugins/service.ts:452
}
if (route.path && requestPath === route.path) {
return true;
}
if (route.pathPrefix && matchesPathPrefix(route.pathPrefix, requestPath)) {
return true;
}
return false;
});
}
async handleGatewayRoute(route: GatewayPluginRouteMatch, request: IncomingMessage, response: ServerResponse): Promise<void> {
if (!this.config) {
throw new Error("Gateway plugin service is not configured.");
}
try {
await route.handler(request, response, this.createRouteContext(route.pluginId));
} catch (error) {
console.warn(`[plugin:${route.pluginId}] Gateway route ${route.id} failed: ${formatError(error)}`);
if (!response.headersSent) {
sendJson(response, 500, { error: { message: formatError(error) } });
} else {
response.destroy(error instanceof Error ? error : new Error(String(error)));
}
}
}
resolveProxyRoute(targetUrl: URL): GatewayPluginProxyRouteMatch | undefined {
let bestMatch: { matchedPathPrefix: string; route: RegisteredProxyRoute } | undefined;
for (const route of this.proxyRoutes) {
const matchedPathPrefix = matchProxyRoute(route, targetUrl);
if (matchedPathPrefix === undefined) {
continue;
}
if (!bestMatch || matchedPathPrefix.length > bestMatch.matchedPathPrefix.length) {
bestMatch = { matchedPathPrefix, route };View on GitHub (pinned to 99f24806c6)
Solutions
- Find the failing handler via pluginId + route id in the log and fix the throw inside it.
- Wrap the handler's fallible work and send a controlled error response instead of throwing.
- Send the response before long async work to avoid destroy-on-late-throw paths.
- Update/reinstall the plugin providing the route.
Example fix
// before
route.handler = async (req, res) => { const id = await lookup(req.query.key); res.end(id.name); };
// after
route.handler = async (req, res) => { const id = await lookup(String(req.query.key)).catch(() => null); if (!id) return sendJson(res, 404, {error:{message:'not found'}}); res.end(id.name); }; Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
null
Prevention
- Never throw from route handlers; send error responses instead
- Send headers early to avoid destroy-on-late-throw
- Handle client aborts explicitly
When it happens
Trigger: A request matching a plugin's registered gateway route (handleRequest dispatch) whose handler throws — unhandled exception, missing route params, or failure of an internal call the handler makes.
Common situations: Plugin route handler bugs on edge-case inputs; handler depending on state (config, auth token) not initialized; client aborting mid-response triggering a write-after-abort throw.
Related errors
- [plugin:${transform.pluginId}] Request transform ${transform
- 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/8c74b8d52f5bbae8.
Report an issue: GitHub.