{"record":{"id":"31490a6e01121e34","repo":"grpc-ecosystem/grpc-gateway","slug":"failed-to-read-grpc-api-configuration-description","errorCode":null,"errorMessage":"failed to read gRPC API Configuration description from %q: %w","messagePattern":"failed to read gRPC API Configuration description from %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/descriptor/grpc_api_configuration.go","lineNumber":68,"sourceCode":"\t\tregistry.AddExternalHTTPRule(selector, rule)\n\t}\n\n\treturn nil\n}\n\n// LoadGrpcAPIServiceFromYAML loads a gRPC API Configuration from the given YAML file\n// and registers the HttpRule descriptions contained in it as externalHTTPRules in\n// the given registry. This must be done before loading the proto file.\n//\n// You can learn more about gRPC API Service descriptions from Google's documentation\n// at https://cloud.google.com/endpoints/docs/grpc/grpc-service-config\n//\n// Note that for the purposes of the gateway generator we only consider a subset of all\n// available features google supports in their service descriptions.\nfunc (r *Registry) LoadGrpcAPIServiceFromYAML(yamlFile string) error {\n\tyamlFileContents, err := os.ReadFile(yamlFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read gRPC API Configuration description from %q: %w\", yamlFile, err)\n\t}\n\n\tservice, err := loadGrpcAPIServiceFromYAML(yamlFileContents, yamlFile)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn registerHTTPRulesFromGrpcAPIService(r, service, yamlFile)\n}\n","sourceCodeStart":50,"sourceCodeEnd":78,"githubUrl":"https://github.com/grpc-ecosystem/grpc-gateway/blob/a58a4436a376a4bcc7d8f10c4d4f919a8438bba9/internal/descriptor/grpc_api_configuration.go#L50-L78","documentation":"Registry.LoadGrpcAPIServiceFromYAML wraps os.ReadFile failures when loading a gRPC API Configuration (grpc.gateway.protoc_gen_openapiv2.options) YAML file. It means the YAML config file could not be read from disk at all, before any parsing happened. The underlying OS error is preserved via %w.","triggerScenarios":"Calling LoadGrpcAPIServiceFromYAML(yamlFile) (e.g. via protoc-gen-openapiv2 with the grpc_api_configuration flag) when the file path does not exist, is a directory, or the process lacks read permission.","commonSituations":"Typo'd or relative config path passed on the protoc command line; file generated in a later build step that hasn't run yet; wrong working directory; CI copying config to a different location than expected.","solutions":["Verify the YAML file exists at the exact path passed (ls <path>) and fix the path","Run protoc from the directory where the config path is relative, or pass an absolute path","Check file permissions (readable by the user running protoc)","Ensure the config file is generated/copied before the protoc step runs in CI"],"exampleFix":"// before\nprotoc --openapiv2_out=... --openapiv2_opt=grpc_api_configuration=./apiconf,yaml my.proto\n// after\nprotoc --openapiv2_out=... --openapiv2_opt=grpc_api_configuration=$(pwd)/apiconf.yaml my.proto","handlingStrategy":"validation","validationCode":"const path = \"apiconf.yaml\"\nif _, err := os.Stat(path); err != nil {\n    return fmt.Errorf(\"gRPC API config %q not readable before load: %w\", path, err)\n}","typeGuard":null,"tryCatchPattern":"cfg, err := reg.LoadGrpcAPIServiceFromYAML(path)\nif err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) {\n        log.Fatalf(\"config file %q unreadable: %v\", pe.Path, pe.Err)\n    }\n    return err\n}","preventionTips":["Use absolute paths or make paths relative to a known base dir","Check file existence in the build script before protoc","Keep config files in the repo so they always exist","Verify permissions in CI containers (non-root users)"],"tags":["filesystem","yaml-config","file-not-found"],"backgroundTag":"file-not-found","analyzedSha":"a58a4436a376a4bcc7d8f10c4d4f919a8438bba9","analyzedAt":"2026-09-02T10:28:31.537Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}