{"record":{"id":"11064f96c280dc96","repo":"grpc/grpc-go","slug":"jwt-token-file-is-required-in-jwt-call-credentials","errorCode":null,"errorMessage":"jwt_token_file is required in JWT call credentials config","messagePattern":"jwt_token_file is required in JWT call credentials config","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/bootstrap/jwtcreds/call_creds.go","lineNumber":47,"sourceCode":"\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":29,"sourceCodeEnd":55,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/bootstrap/jwtcreds/call_creds.go#L29-L55","documentation":"After successfully unmarshalling the JWT call-credentials config, the library checks that jwt_token_file is non-empty (call_creds.go:46-47). A JWT call-credentials entry must point at a token file; an empty value means the configuration is incomplete and the credentials cannot be created.","triggerScenarios":"The config JSON is valid but the jwt_token_file key is missing entirely or set to an empty string. This is a content-level validation distinct from the unmarshal error at index 326.","commonSituations":"The token file path was expected to be injected by a sidecar but the injection failed or the variable was empty; the field name was misspelled (e.g. jwt_file, token_file); the entry was scaffolded as a placeholder and never filled in.","solutions":["Add the jwt_token_file field with the absolute path to a readable JWT token file.","Verify the field name is exactly jwt_token_file (snake_case).","Ensure the token-injecting sidecar or secret mount populates the path before the app reads the bootstrap.","If JWT call creds are not needed, remove the entire call_credentials entry."],"exampleFix":"// before:\n//   { \"type\": \"jwt\", \"config\": {} }\n// after:\n//   { \"type\": \"jwt\", \"config\": { \"jwt_token_file\": \"/var/run/secrets/jwt/token\" } }","handlingStrategy":"validation","validationCode":"// Ensure jwt_token_file is present and non-empty.\nfunc ensureJWTTokenFile(cfg json.RawMessage) error {\n    var probe struct{ JWTTokenFile string `json:\"jwt_token_file\"` }\n    if err := json.Unmarshal(cfg, &probe); err != nil {\n        return err\n    }\n    if probe.JWTTokenFile == \"\" {\n        return errors.New(\"jwt_token_file is required and must be non-empty\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat jwt_token_file as a required string field in any bootstrap schema.","Confirm the token-injecting sidecar populates the path before the client initializes."],"tags":["xds","bootstrap","jwt","credentials","config","required-field","grpc"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}