grpc/grpc-go · error

failed to unmarshal JWT call credentials config

Error message

failed to unmarshal JWT call credentials config: %v

What it means

Returned by jwtcreds.NewCallCredentials when json.Unmarshal of the JWT call creds config fails. The expected config shape (per gRFC A97) is a JSON object with a jwt_token_file string field.

Solutions

  1. Make the call_creds config a JSON object: {"jwt_token_file":"/path/to/token.jwt"}.
  2. Ensure jwt_token_file is a string.
  3. Validate the surrounding call_creds array entry has the right shape {type, config}.

Example fix

// before
{"type":"jwt","config":"/var/secrets/token.jwt"}

// after
{"type":"jwt","config":{"jwt_token_file":"/var/secrets/token.jwt"}}
Defensive patterns

Strategy: validation

Validate before calling

// Validate a JWT call creds config block before bootstrap.
func validateJWTCallCredsConfig(raw json.RawMessage) error {
    var cfg struct {
        JWTTokenFile string `json:"jwt_token_file"`
    }
    if err := json.Unmarshal(raw, &cfg); err != nil {
        return fmt.Errorf("jwt call creds config is not a JSON object: %w", err)
    }
    return nil
}

Try / catch

if _, _, err := jwtcreds.NewCallCredentials(cfg); err != nil {
    if strings.Contains(err.Error(), "failed to unmarshal JWT call credentials config") {
        // reshape config to {"jwt_token_file":"..."}
    }
}

Prevention

When it happens

Trigger: Triggered at call_creds.go:44 when the configJSON passed to NewCallCredentials cannot be unmarshalled into {jwt_token_file string}. Usually the value is not a JSON object or jwt_token_file has a non-string type.

Common situations: call_creds config is a bare string or array; jwt_token_file set to a number/boolean; copy-paste error in the bootstrap call_creds block.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/7992f3bd9183f029. Report an issue: GitHub.

Appendix: source

Thrown at internal/xds/bootstrap/jwtcreds/call_creds.go:44

	"fmt"

	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/credentials/jwt"
)

// NewCallCredentials returns a new JWT token based call credentials. The input
// config must match the structure specified in gRFC A97.
//
// The caller is expected to invoke the cancel function when they are done using
// the returned call creds. This cancel function is idempotent.
func NewCallCredentials(configJSON json.RawMessage) (c credentials.PerRPCCredentials, cancel func(), err error) {
	var cfg struct {
		JWTTokenFile string `json:"jwt_token_file"`
	}
	emptyFn := func() {}

	if err := json.Unmarshal(configJSON, &cfg); err != nil {
		return nil, emptyFn, fmt.Errorf("failed to unmarshal JWT call credentials config: %v", err)
	}
	if cfg.JWTTokenFile == "" {
		return nil, emptyFn, fmt.Errorf("jwt_token_file is required in JWT call credentials config")
	}
	callCreds, err := jwt.NewTokenFileCallCredentials(cfg.JWTTokenFile)
	if err != nil {
		return nil, emptyFn, fmt.Errorf("failed to create JWT call credentials: %v", err)
	}
	return callCreds, emptyFn, nil
}

View on GitHub (pinned to 0c51461d27)