{"record":{"id":"ea01982616565e6e","repo":"grpc/grpc-go","slug":"http-status-d-body-s","errorCode":null,"errorMessage":"http status %d, body: %s","messagePattern":"http status (.+?), body: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/sts/sts.go","lineNumber":320,"sourceCode":"\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// When the http.Client returns a non-nil error, it is the\n\t// responsibility of the caller to read the response body till an EOF is\n\t// encountered and to close it.\n\tbody, err := io.ReadAll(resp.Body)\n\tresp.Body.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode == http.StatusOK {\n\t\treturn body, nil\n\t}\n\tlogger.Warningf(\"http status %d, body: %s\", resp.StatusCode, string(body))\n\treturn nil, fmt.Errorf(\"http status %d, body: %s\", resp.StatusCode, string(body))\n}\n\nfunc tokenInfoFromResponse(respBody []byte) (*tokenInfo, error) {\n\trespData := &responseParameters{}\n\tif err := json.Unmarshal(respBody, respData); err != nil {\n\t\treturn nil, fmt.Errorf(\"json.Unmarshal(%v): %v\", respBody, err)\n\t}\n\tif respData.AccessToken == \"\" {\n\t\treturn nil, fmt.Errorf(\"empty accessToken in response (%v)\", string(respBody))\n\t}\n\treturn &tokenInfo{\n\t\ttokenType:  respData.TokenType,\n\t\ttoken:      respData.AccessToken,\n\t\texpiryTime: time.Now().Add(time.Duration(respData.ExpiresIn) * time.Second),\n\t}, nil\n}\n\n// requestParameters stores all STS request attributes defined in","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/credentials/sts/sts.go#L302-L338","documentation":"Returned by sendRequest in sts/sts.go:320 when the STS HTTP exchange returns a non-2xx status. The full response body is included so the caller can see the token server's error. This is the runtime signal that the token-exchange endpoint rejected the request (auth, scope, subject token, etc.) or was unavailable.","triggerScenarios":"The subject token file is expired or wrong; audience/scope mismatch; the STS endpoint requires different SubjectTokenType; network path returns 4xx/5xx (401, 403, 400, 500, 502); subject/actor token file unreadable upstream.","commonSituations":"Workload identity token expired; misconfigured audience in xDS bootstrap; service-account token audience not matching the STS server; STS endpoint behind a proxy that returns HTML errors; transient 5xx during an outage.","solutions":["Read the response body in the error string to identify the OAuth2 error (invalid_grant, invalid_scope, unauthorized_client).","Verify SubjectTokenPath contents are fresh and match SubjectTokenType; refresh the mounted token.","Confirm Audience/Scope/Resource match what the STS server expects.","For transient 5xx, retry with backoff (the STS creds do not retry automatically)."],"exampleFix":"// before\nopts := sts.Options{\n    SubjectTokenPath: \"/var/run/secrets/expired-token\",\n    Audience: \"wrong-audience\",\n}\n\n// after\nopts := sts.Options{\n    SubjectTokenPath: \"/var/run/secrets/fresh-identity-token\",\n    SubjectTokenType: \"urn:ietf:params:oauth:token-type:jwt\",\n    Audience: \"https://my-grpc-server\",\n}","handlingStrategy":"retry","validationCode":"// Before relying on STS, ensure subject/actor token files are fresh and readable.\nif _, err := os.Stat(opts.SubjectTokenPath); err != nil { return err }\nb, err := os.ReadFile(opts.SubjectTokenPath)\nif err != nil || len(bytes.TrimSpace(b)) == 0 { return errors.New(\"subject token missing\") }","typeGuard":null,"tryCatchPattern":"if st, ok := status.FromError(err); ok && st.Code() == codes.Unavailable {\n    if strings.Contains(st.Message(), \"http status\") {\n        // parse body for OAuth2 error (invalid_grant/invalid_scope/unauthorized_client)\n        // refresh subject token or fix audience/scope; for 5xx, back off and retry\n    }\n}","preventionTips":["Mount fresh, short-lived subject tokens via a sidecar/volume refresh.","Match Audience/Scope/SubjectTokenType to the STS server's expectations.","For transient 5xx, implement a backoff retry around the RPC or a custom PerRPCCreds wrapper."],"tags":["sts","network","authentication","oauth","runtime","go"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}