# Faulty initialization
try:
    invalid_duck = Duck(name="Daffy", age=0, feather_count=-1)
    print(invalid_duck)
except ValidationError as e:
    print(f"Validation Error:\n{e}")
```

In this example, we define a `Duck` data model with three fields: `name`, `age`, and `feather_count`. The `name` field is required and should have a string value, while the `age` and `feather_count` fields are optional and should have integer values.

We use the `Field` class from Pydantic to define additional constraints for the fields. For example, we specify that the `age` field should be greater than or equal to zero, and the `feather_count` field should be greater than or equal to zero, or `None`.

In Python 3.10 and later, we can use the `|` operator for union types ([PEP 604](https://www.python.org/dev/peps/pep-0604/)), allowing us to write `int | None` instead of `Union[int, None]`.

When we try to create an invalid `Duck` instance, Pydantic raises a `ValidationError`. The error message is detailed and helpful:

```bash
Validation Error:
2 validation errors for Duck
age
  Input should be greater than 0 [type=greater_than, input_value=0, input_type=int]
    # link[35:80] https://errors.pydantic.dev/2.8/v/greater_than
    For further information visit https://errors.pydantic.dev/2.8/v/greater_than
feather_count
  Input should be greater than or equal to 0 [type=greater_than_equal, input_value=-1, input_type=int]
    # link[35:86] https://errors.pydantic.dev/2.8/v/greater_than_equal
    For further information visit https://errors.pydantic.dev/2.8/v/greater_than_equal
```

This error message clearly indicates which fields failed validation and why. It specifies that:

1. The 'age' should be greater than 0, but we provided `0`.
2. The 'feather_count' should be greater than or equal to 0, but we provided `-1`.

Detailed error messages make it much easier to identify and fix data validation issues, especially when working with complex data structures or processing user inputs.

## Simplifying Function Validation with Pydantic

While we've seen how Pydantic can validate data in models, it can also be used to validate function arguments directly. This can simplify our code while making it safer to run. Let's revisit our `describe_duck` function using Pydantic's `validate_call` decorator:

```python
from pydantic import BaseModel, Field, validate_call

class DuckDescription(BaseModel):
    name: str
    age: int = Field(gt=0)
    feather_count: int = Field(gt=0)

@validate_call
def describe_duck(duck: DuckDescription) -> str:
    return f"{duck.name} is {duck.age} years old and has {duck.feather_count} feathers."