{"record":{"id":"7992f3bd9183f029","repo":"grpc/grpc-go","slug":"failed-to-unmarshal-jwt-call-credentials-config","errorCode":null,"errorMessage":"failed to unmarshal JWT call credentials config: %v","messagePattern":"failed to unmarshal JWT call credentials config: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/bootstrap/jwtcreds/call_creds.go","lineNumber":44,"sourceCode":"\t\"fmt\"\n\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/jwt\"\n)\n\n// NewCallCredentials returns a new JWT token based call credentials. The input\n// config must match the structure specified in gRFC A97.\n//\n// The caller is expected to invoke the cancel function when they are done using\n// the returned call creds. This cancel function is idempotent.\nfunc NewCallCredentials(configJSON json.RawMessage) (c credentials.PerRPCCredentials, cancel func(), err error) {\n\tvar cfg struct {\n\t\tJWTTokenFile string `json:\"jwt_token_file\"`\n\t}\n\temptyFn := func() {}\n\n\tif err := json.Unmarshal(configJSON, &cfg); err != nil {\n\t\treturn nil, emptyFn, fmt.Errorf(\"failed to unmarshal JWT call credentials config: %v\", err)\n\t}\n\tif cfg.JWTTokenFile == \"\" {\n\t\treturn nil, emptyFn, fmt.Errorf(\"jwt_token_file is required in JWT call credentials config\")\n\t}\n\tcallCreds, err := jwt.NewTokenFileCallCredentials(cfg.JWTTokenFile)\n\tif err != nil {\n\t\treturn nil, emptyFn, fmt.Errorf(\"failed to create JWT call credentials: %v\", err)\n\t}\n\treturn callCreds, emptyFn, nil\n}\n","sourceCodeStart":26,"sourceCodeEnd":55,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/bootstrap/jwtcreds/call_creds.go#L26-L55","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the call_creds config a JSON object: {\"jwt_token_file\":\"/path/to/token.jwt\"}.","Ensure jwt_token_file is a string.","Validate the surrounding call_creds array entry has the right shape {type, config}."],"exampleFix":"// before\n{\"type\":\"jwt\",\"config\":\"/var/secrets/token.jwt\"}\n\n// after\n{\"type\":\"jwt\",\"config\":{\"jwt_token_file\":\"/var/secrets/token.jwt\"}}","handlingStrategy":"validation","validationCode":"// Validate a JWT call creds config block before bootstrap.\nfunc validateJWTCallCredsConfig(raw json.RawMessage) error {\n    var cfg struct {\n        JWTTokenFile string `json:\"jwt_token_file\"`\n    }\n    if err := json.Unmarshal(raw, &cfg); err != nil {\n        return fmt.Errorf(\"jwt call creds config is not a JSON object: %w\", err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if _, _, err := jwtcreds.NewCallCredentials(cfg); err != nil {\n    if strings.Contains(err.Error(), \"failed to unmarshal JWT call credentials config\") {\n        // reshape config to {\"jwt_token_file\":\"...\"}\n    }\n}","preventionTips":["Always make the JWT config a JSON object, not a bare string.","Keep the call_creds array entries shaped as {type, config}.","Validate call_creds blocks with the rest of the bootstrap."],"tags":["grpc","xds","jwt","call-credentials","config","json","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}