grpc/grpc-go · error

empty token_exchange_service_uri in options

Error message

empty token_exchange_service_uri in options

What it means

Returned by sts.validateOptions when Options.TokenExchangeServiceURI is empty. NewCredentials calls validateOptions before constructing the STS call-credential, so this error prevents creating credentials without a token exchange endpoint. The URI is the server that implements RFC 8693 token exchange and is required for the credential to function.

Solutions

  1. Set Options.TokenExchangeServiceURI to a valid http(s) URI before calling NewCredentials.
  2. If the URI comes from config/env, validate it is non-empty before passing it to NewCredentials and log a clear error.
  3. For Google Cloud STS, use the standard endpoint https://sts.googleapis.com/v1/token.

Example fix

// before
creds, err := sts.NewCredentials(sts.Options{}) // empty URI
// after
creds, err := sts.NewCredentials(sts.Options{
    TokenExchangeServiceURI: "https://sts.googleapis.com/v1/token",
    SubjectTokenPath:        "/var/run/secrets/token",
    SubjectTokenType:        "urn:ietf:params:oauth:token-type:jwt",
})
Defensive patterns

Strategy: validation

Validate before calling

if opts.TokenExchangeServiceURI == "" {
    return fmt.Errorf("TokenExchangeServiceURI must be set (e.g., https://sts.googleapis.com/v1/token)")
}
creds, err := sts.NewCredentials(opts)

Prevention

When it happens

Trigger: Calling sts.NewCredentials(sts.Options{}) or any Options struct where TokenExchangeServiceURI is the zero value (empty string). The field is marked Required in the Options struct documentation.

Common situations: Configuration-driven credential setup where the URI is read from an environment variable, a config file, or a bootstrap file that is missing the key. Developers copy example code and forget to fill in the endpoint. Service-mesh or workload-identity setups where the STS endpoint comes from metadata that was not fetched.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/f1a0f53a45f1b611. Report an issue: GitHub.

Appendix: source

Thrown at credentials/sts/sts.go:220

		CheckRedirect: func(*http.Request, []*http.Request) error {
			return http.ErrUseLastResponse
		},
		Timeout: stsRequestTimeout,
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				RootCAs: roots,
			},
		},
	}
}

// validateOptions performs the following validation checks on opts:
// - tokenExchangeServiceURI is not empty
// - tokenExchangeServiceURI is a valid URI with a http(s) scheme
// - subjectTokenPath and subjectTokenType are not empty.
func validateOptions(opts Options) error {
	if opts.TokenExchangeServiceURI == "" {
		return errors.New("empty token_exchange_service_uri in options")
	}
	u, err := url.Parse(opts.TokenExchangeServiceURI)
	if err != nil {
		return err
	}
	if u.Scheme != "http" && u.Scheme != "https" {
		return fmt.Errorf("scheme is not supported: %q. Only http(s) is supported", u.Scheme)
	}

	if opts.SubjectTokenPath == "" {
		return errors.New("required field SubjectTokenPath is not specified")
	}
	if opts.SubjectTokenType == "" {
		return errors.New("required field SubjectTokenType is not specified")
	}
	return nil
}

View on GitHub (pinned to 0c51461d27)