Skip to content

[Feature Request] Include violations in ValidationError's message #546

Description

@stefanvanburen

Feature description:

Include each violation in the message of ValidationError, the way protovalidate-go does, rather than only invalid <MessageName>.

Problem it solves or use case:

str(ValidationError) is invalid <MessageName>, so logs and RPC error messages don't say which field failed or why:

>>> protovalidate.validate(CreateUserRequest(user=User(email="x")))
protovalidate.ValidationError: invalid CreateUserRequest

This has been the message since validate() was added in #32, and both the protobuf-py port (#482) and the native extension (#507) kept it unchanged. The details are only available by inspecting violations or to_proto().

I'm looking at building a protovalidate interceptor for connect-py, the Python counterpart to connectrpc/validate-go. validate-go uses the validation error's message as the Connect error message (connect.Errorf(code, "%s", err.Error())), so Go clients see which fields failed, while Python clients only see invalid CreateUserRequest.

I realize this can be stitched together without this changing here from the exported API, but it seems like a valuable improvement to the default behavior?

Proposed implementation or solution:

Use protovalidate-go's format: ValidationError.Error() gives validation error: <violation> for one violation, or validation errors: followed by \n - <violation> for each when there are several. Each violation is rendered as <field path>: <message>, falling back to [<rule id>] when there's no message. For the example above:

validation error: user.email: must be a valid email address

The violations already carry field, message and rule_id, so only the message string built in Validator.validate (src/lib.rs) would change. Code that matches on the exact invalid <MessageName> text would break, so this may warrant a release note.

Examples or references:

Activity

  1. anuraaga commented on Oct 2, 2026

    @anuraaga
    Contributor

    Thanks for the idea - I think in general it is good for us to align with protovalidate-go. But I'm also a bit worried if it becomes too huge a message. I don't know if I've encountered an error with \n multiple lines in it in Go before and am a bit surprised to see that. Any thoughts on whether this can cause problems by making the messages too large?

  2. stefanvanburen commented on Oct 2, 2026

    @stefanvanburen
    ContributorAuthor

    not sure, honestly. Interestingly, protovalidate-es has a different format that could be better here: https://github.com/bufbuild/protovalidate-es/blob/46bdded5fba862d79a12007600ef57a8cee4839f/packages/protovalidate/src/error.ts#L77-L88. basically, always show the first invalid message and the number of others, if they exist.

    I don't think we need to be fully consistent across languages, so maybe protovalidate-es' approach is better?

  3. anuraaga commented on Oct 5, 2026

    @anuraaga
    Contributor

    Thanks for the reference! I do prefer protovalidate-es's approach. Will ask around for any other thoughts on this.

  4. timostamm commented on Oct 5, 2026

    @timostamm
    Member

    Good catch. Long, multi-line error messages are unusual in JS. That's why protovalidate-es only gives a summary.

    It's also relevant for protovalidate interceptors: the RPC error needs a message, but it doesn't seem great to me to repeat all details in the message that are also available as structured data in the error details.

    It would be great to make this consistent across implementations, and I'm not sure that protovalidate-es is the pattern to follow, but IMO adopting the same summary here would be an incremental improvement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions