{"record":{"id":"e528e36b0ef41855","repo":"googleapis/mcp-toolbox","slug":"failed-to-read-introspection-response-w","errorCode":null,"errorMessage":"failed to read introspection response: %w","messagePattern":"failed to read introspection response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/generic/generic.go","lineNumber":401,"sourceCode":"\t}\n\treq.Header.Set(\"Accept\", \"application/json\")\n\n\t// Send request to auth server's introspection endpoint\n\tresp, err := a.client.Do(req)\n\tif err != nil {\n\t\tlogger.ErrorContext(ctx, \"failed to call introspection endpoint: %v\", err)\n\t\treturn nil, &MCPAuthError{Code: http.StatusInternalServerError, Message: fmt.Sprintf(\"failed to call introspection endpoint: %v\", err), ScopesRequired: a.ScopesRequired}\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tlogger.WarnContext(ctx, \"introspection failed with status: %d\", resp.StatusCode)\n\t\treturn nil, &MCPAuthError{Code: http.StatusUnauthorized, Message: fmt.Sprintf(\"introspection failed with status: %d\", resp.StatusCode), ScopesRequired: a.ScopesRequired}\n\t}\n\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read introspection response: %w\", err)\n\t}\n\n\tvar introspectResp struct {\n\t\tActive   *bool           `json:\"active\"`\n\t\tScope    string          `json:\"scope\"`\n\t\tAud      json.RawMessage `json:\"aud\"`\n\t\tAudience json.RawMessage `json:\"audience\"`\n\t\tExp      json.Number     `json:\"exp\"`\n\t\tIss      string          `json:\"iss\"`\n\t}\n\n\tif err := json.Unmarshal(body, &introspectResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse introspection response: %w\", err)\n\t}\n\n\tif introspectResp.Active == nil || !*introspectResp.Active {\n\t\tlogger.InfoContext(ctx, \"token is not active\")\n\t\treturn nil, &MCPAuthError{Code: http.StatusUnauthorized, Message: \"token is not active\", ScopesRequired: a.ScopesRequired}","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/auth/generic/generic.go#L383-L419","documentation":"The introspection endpoint responded successfully (or with a non-401 status the library proceeds past), and validateOpaqueToken reads the response body — capped at 1 MiB via io.LimitReader — with io.ReadAll. If reading the body fails (connection reset mid-response, context cancelled, TLS error during body read), the error is wrapped with this message.","triggerScenarios":"After sending the introspection request and reading resp.Body, io.ReadAll returns a network or context error — e.g. the authorization server closed the connection before the full body arrived or the request context was cancelled mid-read.","commonSituations":"Unstable network or proxy between toolbox and the IdP, authorization server timeouts killing the connection mid-body, aggressive load balancer idle timeouts, or a context deadline expiring during the read.","solutions":["Retry the request; transient connection resets often resolve on retry.","Check connectivity/proxy/firewall between the toolbox and the introspection endpoint (curl the endpoint directly from the host).","Increase any context/HTTP timeout so the body read is not cut off, and confirm the IdP is healthy."],"exampleFix":"// before: short-lived context cut off mid-read\nctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond)\n// after\nctx, cancel := context.WithTimeout(ctx, 10*time.Second)","handlingStrategy":"retry","validationCode":"// preflight reachability check before real traffic\nresp, err := http.Head(strings.TrimRight(cfg.AuthorizationServer, \"/\") + \"/.well-known/openid-configuration\")\nif err != nil {\n    return fmt.Errorf(\"authorization server unreachable: %w\", err)\n}\nresp.Body.Close()","typeGuard":"null","tryCatchPattern":"var claims map[string]any\nvar err error\nfor attempt := 0; attempt < 3; attempt++ {\n    claims, err = svc.ValidateMCPAuth(ctx, header)\n    if err == nil || !strings.Contains(err.Error(), \"failed to read introspection response\") {\n        break\n    }\n    time.Sleep(time.Duration(1<<attempt) * 100 * time.Millisecond) // transient network error: backoff retry\n}","preventionTips":["Give auth validation a generous context timeout (several seconds)","Monitor IdP/proxy health; connection resets mid-body indicate gateway trouble","Retry transient network errors with exponential backoff"],"tags":["network","http","introspection"],"backgroundTag":"http-response-read-failed","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}