grpc/grpc-go · error

required field SubjectTokenType is not specified

Error message

required field SubjectTokenType is not specified

What it means

Returned by sts.validateOptions (credentials/sts/sts.go:227) when opts.SubjectTokenType is empty. SubjectTokenType is the RFC 8693 token-type identifier (e.g. urn:ietf:params:oauth:token-type:jwt) telling the STS server how to interpret the contents of the subject token file; it is Required in the Options struct (line 101). validateOptions enforces ordering — URI checked first, then SubjectTokenPath, then SubjectTokenType.

Source

Thrown at credentials/sts/sts.go:227

// - 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.tokenMetadata
	}
	return nil
}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Set Options.SubjectTokenType to the correct RFC 8693 URN for your token (commonly urn:ietf:params:oauth:token-type:jwt or urn:ietf:params:oauth:token-type:access_token).
  2. Confirm the type matches the actual contents of the file at SubjectTokenPath.
  3. Validate the whole Options struct up front and fail startup on any empty required field.

Example fix

// before
c, _ := sts.NewCredentials(sts.Options{
    TokenExchangeServiceURI: "https://sts.googleapis.com/v1/token",
    SubjectTokenPath:        "/var/run/secrets/subject-token",
}) // SubjectTokenType 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

// Ensure a non-empty, well-formed token type URN.
var knownTokenTypes = map[string]bool{
    "urn:ietf:params:oauth:token-type:jwt":            true,
    "urn:ietf:params:oauth:token-type:access_token":   true,
    "urn:ietf:params:oauth:token-type:id_token":       true,
    "urn:ietf:params:oauth:token-type:saml2":          true,
}
if opts.SubjectTokenType == "" || !knownTokenTypes[opts.SubjectTokenType] {
    return fmt.Errorf("SubjectTokenType %q unknown/empty", opts.SubjectTokenType)
}

Try / catch

c, err := sts.NewCredentials(opts)
if err != nil { log.Fatalf("STS creds: %v", err) }

Prevention

When it happens

Trigger: Calling sts.NewCredentials with SubjectTokenType unset or empty. Because validateOptions checks SubjectTokenPath before SubjectTokenType, you only see this error once SubjectTokenPath is already set.

Common situations: Forgetting the token-type URN (it is long and easy to omit); copy-pasting an Options literal that left it blank; using a wrong key name in JSON config so the field stays zero-value.

Related errors


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