Protoc-gen-validate (Python)
Protoc-gen-validate provides robust data validation for Protocol Buffers. This Python library serves as the runtime component for validation code generated by the `protoc-gen-validate` plugin. It allows Python applications to enforce complex validation rules defined directly within `.proto` files, ensuring data integrity at the message level. The current version is 1.3.3, with releases often occurring to fix packaging or Python version compatibility issues.
Common errors
-
protoc-gen-validate: program not found or is not executable
cause The `protoc-gen-validate` binary (the `protoc` plugin) is not installed or not in your system's PATH.fixDownload the `protoc-gen-validate` binary from GitHub releases or install it via `go install github.com/bufbuild/protoc-gen-validate/cmd/protoc-gen-validate@latest` and ensure the binary is accessible in your system's PATH. -
ModuleNotFoundError: No module named 'your_message_pb2_validate'
cause The Python validation code for your protobuf messages (`your_message_pb2_validate.py`) was either not generated, or the generated files are not in Python's import path.fixEnsure you run `protoc --plugin=protoc-gen-validate --validate_out=. --python_out=. your_message.proto` correctly, and that the generated `_pb2_validate.py` file is located where your Python interpreter can find it. -
AttributeError: module 'my_message_pb2' has no attribute 'validate'
cause You are attempting to call a `validate` method directly on the `_pb2` module, which only contains the protobuf message definitions. The validation logic is encapsulated in the *generated* `_pb2_validate` module.fixImport the specific `validate` function from your generated validation module: `from my_message_pb2_validate import validate as validate_my_message`. -
ValidationError: <details about failure>
cause This is the expected behavior. The protobuf message or one of its fields failed to meet the validation rules defined in your `.proto` file.fixReview the validation rules in your `.proto` definitions (e.g., `(validate.rules).field.rule = value`) and inspect the `ValidationError` message for details on which specific field caused the failure. Adjust your input data or validation rules accordingly.
Warnings
- gotcha The PyPI package `protoc-gen-validate` provides only the Python runtime library for generated validation code. You must separately install the `protoc-gen-validate` binary (the `protoc` plugin) to generate the Python validation files (`_pb2_validate.py`).
- gotcha Validation is not automatic. After generation, you must explicitly import the `validate` function from your generated `_pb2_validate.py` module and call it with your message instance. Simply importing the `_pb2.py` message definition is insufficient.
- breaking Python 3.9 support was unstable in earlier `v1.x` versions, with explicit fixes in `v1.2.1`. From `v1.3.3` onwards, the official `requires_python` is `>=3.10`. Using older versions of the library with Python 3.9+ may lead to build or runtime issues.
- gotcha The `ValidationError` exception must be imported from `protoc_gen_validate.validator`. Attempting to import it from the top-level package or using a generic `Exception` will prevent proper handling of specific validation failures.
Install
-
pip install protoc-gen-validate
Imports
- ValidationError
from protoc_gen_validate import ValidationError
from protoc_gen_validate.validator import ValidationError
Quickstart
# This quickstart assumes you have already defined a .proto file with validation rules
# (e.g., example.proto) and generated the Python protobuf and validation stubs:
#
# example.proto content:
# syntax = "proto3";
# package example;
# import validate/validate.proto;
#
# message Person {
# int32 id = 1 [(validate.rules).int32.gt = 0];
# string email = 2 [(validate.rules).string.email = true];
# string name = 3 [(validate.rules).string.min_len = 1];
# }
#
# Generation command (requires 'protoc' and 'protoc-gen-validate' binaries):
# protoc --plugin=protoc-gen-validate --validate_out=. --python_out=. example.proto
from example_pb2 import Person
from example_pb2_validate import validate as validate_person
from protoc_gen_validate.validator import ValidationError
# --- Example 1: Valid Person ---
print("\n--- Valid Person Example ---")
try:
p_valid = Person(id=1, email="alice@example.com", name="Alice Smith")
validate_person(p_valid)
print(f"Validation successful for: {p_valid.name}")
except ValidationError as e:
print(f"Validation unexpectedly failed for valid person: {e}")
# --- Example 2: Invalid Person (id <= 0) ---
print("\n--- Invalid Person (ID) Example ---")
try:
p_invalid_id = Person(id=0, email="bob@example.com", name="Bob Johnson")
validate_person(p_invalid_id)
print(f"Validation unexpectedly passed for invalid ID: {p_invalid_id.name}")
except ValidationError as e:
print(f"Validation failed for invalid ID (as expected): {e}")
# --- Example 3: Invalid Person (empty name) ---
print("\n--- Invalid Person (Name) Example ---")
try:
p_invalid_name = Person(id=2, email="charlie@example.com", name="")
validate_person(p_invalid_name)
print(f"Validation unexpectedly passed for empty name: {p_invalid_name.email}")
except ValidationError as e:
print(f"Validation failed for empty name (as expected): {e}")