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

  1. Find the failing handler via pluginId + route id in the log and fix the throw inside it.
  2. Wrap the handler's fallible work and send a controlled error response instead of throwing.
  3. Send the response before long async work to avoid destroy-on-late-throw paths.
  4. 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

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


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/8c74b8d52f5bbae8. Report an issue: GitHub.