{"record":{"id":"f1a0f53a45f1b611","repo":"grpc/grpc-go","slug":"empty-token-exchange-service-uri-in-options","errorCode":null,"errorMessage":"empty token_exchange_service_uri in options","messagePattern":"empty token_exchange_service_uri in options","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/sts/sts.go","lineNumber":220,"sourceCode":"\t\tCheckRedirect: func(*http.Request, []*http.Request) error {\n\t\t\treturn http.ErrUseLastResponse\n\t\t},\n\t\tTimeout: stsRequestTimeout,\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: &tls.Config{\n\t\t\t\tRootCAs: roots,\n\t\t\t},\n\t\t},\n\t}\n}\n\n// validateOptions performs the following validation checks on opts:\n// - tokenExchangeServiceURI is not empty\n// - tokenExchangeServiceURI is a valid URI with a http(s) scheme\n// - subjectTokenPath and subjectTokenType are not empty.\nfunc validateOptions(opts Options) error {\n\tif opts.TokenExchangeServiceURI == \"\" {\n\t\treturn errors.New(\"empty token_exchange_service_uri in options\")\n\t}\n\tu, err := url.Parse(opts.TokenExchangeServiceURI)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif u.Scheme != \"http\" && u.Scheme != \"https\" {\n\t\treturn fmt.Errorf(\"scheme is not supported: %q. Only http(s) is supported\", u.Scheme)\n\t}\n\n\tif opts.SubjectTokenPath == \"\" {\n\t\treturn errors.New(\"required field SubjectTokenPath is not specified\")\n\t}\n\tif opts.SubjectTokenType == \"\" {\n\t\treturn errors.New(\"required field SubjectTokenType is not specified\")\n\t}\n\treturn nil\n}\n","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/credentials/sts/sts.go#L202-L238","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set Options.TokenExchangeServiceURI to a valid http(s) URI before calling NewCredentials.","If the URI comes from config/env, validate it is non-empty before passing it to NewCredentials and log a clear error.","For Google Cloud STS, use the standard endpoint https://sts.googleapis.com/v1/token."],"exampleFix":"// before\ncreds, err := sts.NewCredentials(sts.Options{}) // empty URI\n// after\ncreds, err := sts.NewCredentials(sts.Options{\n    TokenExchangeServiceURI: \"https://sts.googleapis.com/v1/token\",\n    SubjectTokenPath:        \"/var/run/secrets/token\",\n    SubjectTokenType:        \"urn:ietf:params:oauth:token-type:jwt\",\n})","handlingStrategy":"validation","validationCode":"if opts.TokenExchangeServiceURI == \"\" {\n    return fmt.Errorf(\"TokenExchangeServiceURI must be set (e.g., https://sts.googleapis.com/v1/token)\")\n}\ncreds, err := sts.NewCredentials(opts)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate all required STS Options fields before calling NewCredentials.","Load the URI from a well-known config key and fail fast if missing.","Use the Google Cloud standard STS endpoint as a documented default."],"tags":["go","grpc","sts","credentials","validation"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}