grpc/grpc-go · error
failed to create http request: %v
Error message
failed to create http request: %v
What it means
Returned by constructRequest in sts/sts.go:291 when http.NewRequestWithContext fails while building the POST to the token-exchange endpoint. NewRequestWithContext fails on a malformed URL (e.g. control characters, bad escaping) or on a nil/invalid context. The wrapped %v is the underlying error.
Source
Thrown at credentials/sts/sts.go:291
RequestedTokenType: opts.RequestedTokenType,
SubjectToken: string(subToken),
SubjectTokenType: opts.SubjectTokenType,
}
if opts.ActorTokenPath != "" {
actorToken, err := readActorTokenFrom(opts.ActorTokenPath)
if err != nil {
return nil, err
}
reqParams.ActorToken = string(actorToken)
reqParams.ActorTokenType = opts.ActorTokenType
}
jsonBody, err := json.Marshal(reqParams)
if err != nil {
return nil, err
}
req, err := http.NewRequestWithContext(ctx, "POST", opts.TokenExchangeServiceURI, bytes.NewBuffer(jsonBody))
if err != nil {
return nil, fmt.Errorf("failed to create http request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
return req, nil
}
func sendRequest(client httpDoer, req *http.Request) ([]byte, error) {
// http.Client returns a non-nil error only if it encounters an error
// caused by client policy (such as CheckRedirect), or failure to speak
// HTTP (such as a network connectivity problem). A non-2xx status code
// doesn't cause an error.
resp, err := client.Do(req)
if err != nil {
return nil, err
}
// When the http.Client returns a non-nil error, it is the
// responsibility of the caller to read the response body till an EOF is
// encountered and to close it.View on GitHub (pinned to 03255a9237)
Solutions
- Sanitize and re-validate TokenExchangeServiceURI with url.ParseRequestURI before calling NewCredentials.
- Ensure the context passed into the RPC (and thus GetRequestMetadata) is non-nil and not pre-canceled.
- Strip whitespace/control characters from the configured URI.
Example fix
// before
opts := sts.Options{TokenExchangeServiceURI: strings.TrimSpace(rawURI) + "\r\n", ...}
// after
u, err := url.ParseRequestURI(strings.TrimSpace(rawURI))
if err != nil { return err }
opts := sts.Options{TokenExchangeServiceURI: u.String(), ...} Defensive patterns
Strategy: validation
Validate before calling
u, err := url.ParseRequestURI(strings.TrimSpace(opts.TokenExchangeServiceURI))
if err != nil { return fmt.Errorf("invalid STS request URI: %w", err) }
opts.TokenExchangeServiceURI = u.String()
// also ensure the RPC context passed in is non-nil and not pre-canceled
stsCreds, err := sts.NewCredentials(opts) Try / catch
if strings.Contains(err.Error(), "failed to create http request") {
// URI malformed for net/http; sanitize or the context was nil/canceled
} Prevention
- Sanitize the STS URI (trim whitespace/control chars) at config load.
- Validate with url.ParseRequestURI, which is stricter than url.Parse.
- Never pass a nil context to RPCs that use STS per-RPC creds.
When it happens
Trigger: TokenExchangeServiceURI parses (passes validateOptions) but is structurally invalid for http.NewRequest; the passed context is nil; the URI contains characters the URL parser in NewRequest rejects.
Common situations: A URI that passed url.Parse but trips net/http's stricter validation; a context that was already canceled and somehow nil-wrapped; copy-paste of a URL with embedded credentials or whitespace.
Related errors
- empty accessToken in response (%v)
- scheme is not supported: %q. Only http(s) is supported
- http status %d, body: %s
- json.Unmarshal(%v): %v
- empty token_exchange_service_uri in options
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/20466f8e0ff16691.
Report an issue: GitHub.