grpc/grpc-go · error
required field SubjectTokenPath is not specified
Error message
required field SubjectTokenPath is not specified
What it means
Returned by sts.validateOptions (credentials/sts/sts.go:224) when opts.SubjectTokenPath is empty. The subject token is the file containing the identity token of the party on whose behalf the exchange is made; it is marked Required in the Options struct comment (line 96). Without it the STS request cannot include subject_token, so NewCredentials refuses to construct.
Source
Thrown at credentials/sts/sts.go:224
// 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
}
// cachedMetadata returns the cached metadata provided it is not going to
// expire anytime soon.
//
// Caller must hold c.mu.
func (c *callCreds) cachedMetadata() map[string]string {
now := time.Now()
// If the cached token has not expired and the lifetime remaining on that
// token is greater than the minimum value we are willing to accept, go
// ahead and use it.
if c.tokenExpiry.After(now) && c.tokenExpiry.Sub(now) > minCachedTokenLifetime {
return c.tokenMetadataView on GitHub (pinned to 03255a9237)
Solutions
- Set Options.SubjectTokenPath to the absolute path of the file containing your subject (identity) token.
- Verify the path exists and is readable before calling NewCredentials (see also error 20).
- Check the returned error from NewCredentials and surface it in startup logs.
Example fix
// before
c, _ := sts.NewCredentials(sts.Options{
TokenExchangeServiceURI: "https://sts.googleapis.com/v1/token",
SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
}) // SubjectTokenPath missing
// after
c, err := sts.NewCredentials(sts.Options{
TokenExchangeServiceURI: "https://sts.googleapis.com/v1/token",
SubjectTokenPath: "/var/run/secrets/subject-token",
SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
}) Defensive patterns
Strategy: validation
Validate before calling
if opts.SubjectTokenPath == "" {
return errors.New("SubjectTokenPath must be set to a readable token file")
}
if fi, err := os.Stat(opts.SubjectTokenPath); err != nil || fi.IsDir() {
return fmt.Errorf("SubjectTokenPath %q not usable: %w", opts.SubjectTokenPath, err)
} Try / catch
c, err := sts.NewCredentials(opts)
if err != nil {
log.Fatalf("cannot build STS creds: %v", err)
} Prevention
- Treat SubjectTokenPath as required in your own config schema.
- Stat-check the file before passing the option.
- Fail the process at startup rather than mid-RPC.
When it happens
Trigger: Calling sts.NewCredentials with SubjectTokenPath unset (or empty). The check runs only inside NewCredentials/validateOptions, so this surfaces immediately at construction time.
Common situations: Config loaded from a file/env that omits the subject token file path (common when migrating from in-memory tokens to file-based tokens); path field named differently in config vs struct; expecting a default but none exists.
Related errors
- empty token_exchange_service_uri in options
- required field SubjectTokenType is not specified
- missing fallback credentials
- token file access error
- pemfile: certificate and key file must be in the same direct
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/2a666df32e4d54d7.
Report an issue: GitHub.