googleapis/mcp-toolbox · error
Failed to encode PRM response
Error message
Failed to encode PRM response
What it means
In the Protected Resource Metadata (PRM) HTTP handler, after building the JSON response the server tries to json.Encode it into the http.ResponseWriter. If writing to the response stream fails (client disconnected, broken pipe, TLS/network error mid-response), Encode returns an error and the server logs "Failed to encode PRM response" and attempts a 500 response.
Source
Thrown at internal/server/mcp.go:913
for _, authSvc := range s.PrimitiveMgr.AuthServices() {
if mSvc, ok := authSvc.(auth.MCPAuthService); ok && mSvc.IsMCPEnabled() {
server = mSvc.GetAuthorizationServer()
scopes = mSvc.GetScopesRequired()
break
}
}
res := prmResponse{
Resource: s.toolboxUrl,
AuthorizationServers: []string{server},
ScopesSupported: scopes,
BearerMethodsSupported: []string{"header"},
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(res); err != nil {
s.logger.ErrorContext(r.Context(), fmt.Sprintf("Failed to encode PRM response: %v", err))
http.Error(w, "Failed to encode PRM response", http.StatusInternalServerError)
}
}
View on GitHub (pinned to 8cc6e09de2)
Solutions
- Retry the discovery request from the client; this is usually a transient transport failure
- Increase the client/proxy read timeout so the PRM response can complete
- Check server logs for the underlying encoding error detail to confirm client disconnect vs server issue
- Verify network path (LB, ingress) isn't terminating responses early
Example fix
// before (client side)
const res = await fetch(url);
// after (client side, with timeout headroom)
const res = await fetch(url, { signal: AbortSignal.timeout(30000) }); Defensive patterns
Strategy: retry
Validate before calling
// client: check connectivity before fetching PRM
const url = new URL(baseUrl + '/.well-known/oauth-protected-resource');
if (!['http:', 'https:'].includes(url.protocol)) throw new Error('bad base URL'); Try / catch
// client side
try {
const res = await fetch(prmUrl, { signal: AbortSignal.timeout(30000) });
if (!res.ok) throw new Error(`PRM request failed: ${res.status}`);
const prm = await res.json();
} catch (e) {
if (e.name === 'TimeoutError' || e.name === 'AbortError') retryFetch(prmUrl);
else throw e;
} Prevention
- Set client timeouts generously for OAuth discovery endpoints
- Avoid closing connections immediately after issuing the discovery request
- Configure LBs/proxies to keep the connection alive until the small JSON body is delivered
- Monitor server logs for repeated PRM encode errors indicating client/proxy misbehavior
When it happens
Trigger: A client closes the connection or times out while the PRM endpoint (e.g. GET /.well-known/oauth-protected-resource) is streaming the JSON body; the underlying TCP connection errors during Write.
Common situations: Aggressive client timeouts in OAuth discovery flows; load balancers closing idle keep-alive connections; client cancels the request right after headers are sent; proxy buffering limits.
Related errors
- failed to fetch OIDC config: %w
- failed to create introspection request: %w
- failed to read introspection response: %w
- failed to parse introspection response: %w
- failed to decode Google tokeninfo response: %w
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/d2607e5e8cba3930.
Report an issue: GitHub.