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 (credentials/sts/sts.go:213) when opts.TokenExchangeServiceURI is the empty string. NewCredentials calls validateOptions before building the STS call-credentials instance, so this is a hard constructor failure: the STS plugin (RFC 8693 token exchange) cannot know which server to POST the token-exchange request to without a URI, so it refuses to construct.

Source

Thrown at credentials/sts/sts.go:213

func makeHTTPClient(roots *x509.CertPool) httpDoer {
	return &http.Client{
		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 03255a9237)

Solutions

  1. Set Options.TokenExchangeServiceURI to the STS endpoint URL before calling NewCredentials.
  2. Always check the error returned by sts.NewCredentials and fail fast if non-nil.
  3. Validate the config struct in your own config-loading layer (non-empty + http(s) scheme) before passing it to NewCredentials.

Example fix

// before
c, err := sts.NewCredentials(sts.Options{
    SubjectTokenPath: "/var/run/secrets/token",
    SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
}) // err: empty token_exchange_service_uri

// after
c, 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

// Validate STS Options before constructing credentials.
func validateSTS(o sts.Options) error {
    if o.TokenExchangeServiceURI == "" {
        return errors.New("TokenExchangeServiceURI is required")
    }
    if u, err := url.Parse(o.TokenExchangeServiceURI); err != nil || (u.Scheme != "http" && u.Scheme != "https") {
        return fmt.Errorf("TokenExchangeServiceURI must be http(s), got %q", o.TokenExchangeServiceURI)
    }
    if o.SubjectTokenPath == "" {
        return errors.New("SubjectTokenPath is required")
    }
    if o.SubjectTokenType == "" {
        return errors.New("SubjectTokenType is required")
    }
    return nil
}

if err := validateSTS(opts); err != nil { log.Fatal(err) }
c, err := sts.NewCredentials(opts)

Try / catch

c, err := sts.NewCredentials(opts)
if err != nil {
    // err contains the exact missing-field message; log and abort startup
    log.Fatalf("STS credentials invalid: %v", err)
}

Prevention

When it happens

Trigger: Calling sts.NewCredentials(Options{...}) without setting TokenExchangeServiceURI, or with it explicitly empty. Any subsequent code that ignores the returned error and tries to use the nil credentials will then panic.

Common situations: Reading the STS Options from a JSON/env config and the field is absent or misnamed; copy-pasting a sample that omits the field; refactoring that renamed the struct field; config templating that renders an empty value.

Related errors


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