{"record":{"id":"2a666df32e4d54d7","repo":"grpc/grpc-go","slug":"required-field-subjecttokenpath-is-not-specified","errorCode":null,"errorMessage":"required field SubjectTokenPath is not specified","messagePattern":"required field SubjectTokenPath is not specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/sts/sts.go","lineNumber":231,"sourceCode":"\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\n\t// token is greater than the minimum value we are willing to accept, go\n\t// ahead and use it.\n\tif c.tokenExpiry.After(now) && c.tokenExpiry.Sub(now) > minCachedTokenLifetime {\n\t\treturn c.tokenMetadata","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/credentials/sts/sts.go#L213-L249","documentation":"Returned by sts.validateOptions when Options.SubjectTokenPath is empty. The subject token is the security token (e.g., a Kubernetes service-account JWT or a VM identity token) that the STS client exchanges for an access token; without a file path to read it from, the token exchange cannot be constructed.","triggerScenarios":"Calling sts.NewCredentials with an Options struct where SubjectTokenPath is not set (empty string). This is a required field validated after the TokenExchangeServiceURI check.","commonSituations":"Config files that map STS options from bootstrap data but omit the subject_token_path key. Workload-identity setups where the path is supposed to be injected by the runtime but the injection failed or the key name changed between versions.","solutions":["Set Options.SubjectTokenPath to the filesystem path of the subject token file (e.g., /var/run/secrets/tokens/token).","Confirm the file is readable by the process before creating the credentials.","If the path is templated from config, validate the template resolved to a non-empty value."],"exampleFix":"// before\nopts := sts.Options{\n    TokenExchangeServiceURI: \"https://sts.googleapis.com/v1/token\",\n    // SubjectTokenPath missing\n}\n// after\nopts := sts.Options{\n    TokenExchangeServiceURI: \"https://sts.googleapis.com/v1/token\",\n    SubjectTokenPath:        \"/var/run/secrets/tokens/sa-token\",\n}","handlingStrategy":"validation","validationCode":"if opts.SubjectTokenPath == \"\" {\n    return fmt.Errorf(\"SubjectTokenPath must be set to a readable token file\")\n}\nif _, err := os.Stat(opts.SubjectTokenPath); err != nil {\n    return fmt.Errorf(\"subject token file not accessible: %w\", err)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set SubjectTokenPath to the path of the subject token file.","Verify the file is readable at startup.","For workload identity, confirm the token injection path matches the configured value."],"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"}