{"record":{"id":"6b334513eeabc381","repo":"grpc/grpc-go","slug":"scheme-is-not-supported-q-only-http-s-is-suppo","errorCode":null,"errorMessage":"scheme is not supported: %q. Only http(s) is supported","messagePattern":"scheme is not supported: %q\\. Only http\\(s\\) is supported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/sts/sts.go","lineNumber":220,"sourceCode":"\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\n// cachedMetadata returns the cached metadata provided it is not going to\n// expire anytime soon.\n//\n// Caller must hold c.mu.\nfunc (c *callCreds) cachedMetadata() map[string]string {\n\tnow := time.Now()\n\t// If the cached token has not expired and the lifetime remaining on that","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/credentials/sts/sts.go#L202-L238","documentation":"Returned by validateOptions in sts/sts.go:220 when the parsed TokenExchangeServiceURI's scheme is neither http nor https. STS token exchange (RFC 8693) is performed over a plain HTTP request, so any other scheme (grpc://, dns://, unix:) is rejected at construction time.","triggerScenarios":"Setting Options.TokenExchangeServiceURI to a gRPC target, a dns:/// resolver URI, a bare hostname without scheme, or any non-http(s) URL when calling sts.NewCredentials.","commonSituations":"Confusing the STS endpoint URL with the gRPC server target; xDS bootstrap generated with a grpc:// or xds:// scheme for the token exchange; omitting the https:// prefix.","solutions":["Set TokenExchangeServiceURI to a fully-qualified http(s) URL (e.g. https://sts.googleapis.com/v1/token).","Regenerate/fix the xDS bootstrap so the token_exchange_service_uri field is an http(s) URL.","If a non-TLS endpoint is acceptable for testing, use http:// explicitly."],"exampleFix":"// before\nopts := sts.Options{TokenExchangeServiceURI: \"grpc://sts.example.com:443\", ...}\n\n// after\nopts := sts.Options{TokenExchangeServiceURI: \"https://sts.example.com/v1/token\", ...}","handlingStrategy":"validation","validationCode":"u, err := url.Parse(opts.TokenExchangeServiceURI)\nif err != nil { return fmt.Errorf(\"bad STS URI: %w\", err) }\nif u.Scheme != \"http\" && u.Scheme != \"https\" {\n    return fmt.Errorf(\"STS URI must be http(s), got %q\", u.Scheme)\n}\nstsCreds, err := sts.NewCredentials(opts)\nif err != nil { return err }","typeGuard":null,"tryCatchPattern":"stsCreds, err := sts.NewCredentials(opts)\nif err != nil {\n    if strings.Contains(err.Error(), \"scheme is not supported\") {\n        // fix TokenExchangeServiceURI to an http(s) URL\n    }\n    return err\n}","preventionTips":["Always store the STS endpoint as a full http(s) URL in config/bootstrap.","Do not confuse the gRPC server target with the STS token endpoint.","Validate the scheme at config-load time, not just at dial time."],"tags":["sts","validation","configuration","url","go"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}