Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ValidationError.from_exception_data doesn't work with error type: 'ip_v4_address'" #963

Open
mikedavidson-evertz opened this issue Sep 15, 2023 · 3 comments
Assignees

Comments

@mikedavidson-evertz
Copy link

Describe the bug

When constructing validation errors using ValidationError.from_exception_data, this fails when the error type is ip_v4_address.It will raise:

KeyError: "Invalid error type: 'ip_v4_address'

To Reproduce
Run the code below. It uses a custom model validator that manually constructs the validation error using ValidationError.from_exception_data

from pydantic import BaseModel, Field, model_validator, ValidationError
from ipaddress import IPv4Address
from pydantic_core import InitErrorDetails


class OutputStream(BaseModel):
    destination_ip: IPv4Address = Field(
        ...,
    )


class StreamingDevice(BaseModel):
    output_stream: OutputStream = Field(
        ...,
    )

    @model_validator(mode="before")
    @classmethod
    def validate_model(cls, data: dict) -> dict:
        validation_errors: list[InitErrorDetails] = []

        if data.get("output_stream") is not None:
            try:
                OutputStream.model_validate(data["output_stream"])
            except ValidationError as e:
                validation_errors.extend(e.errors())

        if validation_errors:
            raise ValidationError.from_exception_data(title=cls.__name__, line_errors=validation_errors)

        return data



streaming_device_payload = {"output_stream": {"destination_ip": "123"}}
streaming_device = StreamingDevice.model_validate(streaming_device_payload)

Expected behavior
Pydantic is capable of generating 'ip_v4_address' errors when using model validation without the custom model validator. Therefore, we should be able to manually construct the validation error using the error dictionary that contains the ip_v4_address error type as input into ValidationError.from_exception_data.

If you were to remove the custom model validator in the example above, Pydantic would successfully throw that error type:

pydantic_core._pydantic_core.ValidationError: 1 validation error for StreamingDevice
output_stream.destination_ip
  Input is not a valid IPv4 address [type=ip_v4_address, input_value='123', input_type=str

Haven't tested it, but should ip_v4_address be in this error list here?
https://github.com/pydantic/pydantic-core/blob/main/python/pydantic_core/core_schema.py#L3900

Version:

  • OS: Ubuntu 20.04.4 LTS
  • Python version: 3.9.16
  • pydantic version: 2.3.0
@westrachel
Copy link

I'm running into a similar issue where ValidationError.from_exception_data doesn't work with other error types, specifically value_error and enum.

Reproducing the Errors:
(1) enum

from pydantic_core import InitErrorDetails
from pydantic import ValidationError

validation_errors = []

validation_errors.append(InitErrorDetails(
    type="enum",
    loc=("direction",),
    input="Z",
))

raise ValidationError.from_exception_data(
    title="example",
    line_errors=validation_errors
)

# Result:
Traceback (most recent call last):
  File ".../example.py", line 12, in <module>
    raise ValidationError.from_exception_data(
TypeError: Enum: 'expected' required in context

(2) value_error

from pydantic_core import InitErrorDetails
from pydantic import ValidationError

validation_errors = []

validation_errors.append(InitErrorDetails(
    type="value_error",
    loc=("direction",),
    input="Z",
))

raise ValidationError.from_exception_data(
    title="example",
    line_errors=validation_errors
)

# Result:
Traceback (most recent call last):
  File ".../example.py", line 12, in <module>
    raise ValidationError.from_exception_data(
TypeError: ValueError: 'error' required in context

Expected Behavior:

Instead of the TypeErrors raised above, I expect a pydantic ValidationError to be raised that shows relevant info for the respective enum and value_error types. For example, If I assign type in InitErrorDetails in the above code to an error that does not fully fit my use case (string_type), it does work and does produce the validation error I want to raise (but with the wrong message; I don't want the invalid string message for my use case):

from pydantic_core import InitErrorDetails
from pydantic import ValidationError

validation_errors = []

validation_errors.append(InitErrorDetails(
    type="string_type",
    loc=("direction",),
    input="Z",
))

raise ValidationError.from_exception_data(
    title="example",
    line_errors=validation_errors
)

# Result:
Traceback (most recent call last):
  File ".../example.py", line 12, in <module>
    raise ValidationError.from_exception_data(
pydantic_core._pydantic_core.ValidationError: 1 validation error for example
direction
  Input should be a valid string [type=string_type, input_value='Z', input_type=str]
    For further information visit https://errors.pydantic.dev/2.5/v/string_type

Versions:
OS: macOS Sonoma 14.1.1
Python version: 3.10.12
pydantic version: 2.5.2

@KeynesYouDigIt
Copy link

KeynesYouDigIt commented Feb 24, 2024

I am having the same issues. The new things like @model_validator are an exciting direction, but we really need support on how to properly aggregate custom errors in this case.

When trying to aggregate errors, I am really struggling. Is this a sign I am using pydantic not as intended? if not, are there more complex cases in the docs?

If I am using this as intended, here were debug steps
specific error I am getting - TypeError: ValueError: 'error' required in context.

I looked at the Init error typed dict..... nothing jumps out as to what was wrong in my case.

class InitErrorDetails(_TypedDict):

@dsayling
Copy link

dsayling commented Apr 4, 2024

@KeynesYouDigIt

It's complaining about there being no error in the ctx dict

e.g.

...
            InitErrorDetails(
                {
                    "type": "value_error",
                    "loc": (info.field_name,),
                    "input": v,
                    "ctx": {
                        "error": f"your_message {v}",
                    },
                }
            )

edit

Also, depending on the "type" here, the ctx might need different key values. See the linked doc page and scroll down to ctx

As far as I know, you can inspect what needs to be in the ctx to render the error by doing

from pydantic_core._pydantic_core import list_all_errors
list_all_errors()

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

No branches or pull requests

6 participants