grpc-ecosystem/grpc-gateway · error

failed to read gRPC API Configuration description from %q: %

Error message

failed to read gRPC API Configuration description from %q: %w

What it means

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.

Source

Thrown at internal/descriptor/grpc_api_configuration.go:68

		registry.AddExternalHTTPRule(selector, rule)
	}

	return nil
}

// LoadGrpcAPIServiceFromYAML loads a gRPC API Configuration from the given YAML file
// and registers the HttpRule descriptions contained in it as externalHTTPRules in
// the given registry. This must be done before loading the proto file.
//
// You can learn more about gRPC API Service descriptions from Google's documentation
// at https://cloud.google.com/endpoints/docs/grpc/grpc-service-config
//
// Note that for the purposes of the gateway generator we only consider a subset of all
// available features google supports in their service descriptions.
func (r *Registry) LoadGrpcAPIServiceFromYAML(yamlFile string) error {
	yamlFileContents, err := os.ReadFile(yamlFile)
	if err != nil {
		return fmt.Errorf("failed to read gRPC API Configuration description from %q: %w", yamlFile, err)
	}

	service, err := loadGrpcAPIServiceFromYAML(yamlFileContents, yamlFile)
	if err != nil {
		return err
	}

	return registerHTTPRulesFromGrpcAPIService(r, service, yamlFile)
}

View on GitHub (pinned to a58a4436a3)

Solutions

  1. Verify the YAML file exists at the exact path passed (ls <path>) and fix the path
  2. Run protoc from the directory where the config path is relative, or pass an absolute path
  3. Check file permissions (readable by the user running protoc)
  4. Ensure the config file is generated/copied before the protoc step runs in CI

Example fix

// before
protoc --openapiv2_out=... --openapiv2_opt=grpc_api_configuration=./apiconf,yaml my.proto
// after
protoc --openapiv2_out=... --openapiv2_opt=grpc_api_configuration=$(pwd)/apiconf.yaml my.proto
Defensive patterns

Strategy: validation

Validate before calling

const path = "apiconf.yaml"
if _, err := os.Stat(path); err != nil {
    return fmt.Errorf("gRPC API config %q not readable before load: %w", path, err)
}

Try / catch

cfg, err := reg.LoadGrpcAPIServiceFromYAML(path)
if err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) {
        log.Fatalf("config file %q unreadable: %v", pe.Path, pe.Err)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02). Data as JSON: /api/errors/31490a6e01121e34. Report an issue: GitHub.