Repository: litestar-org/litestar

Issue:
Bug: incorrect message in ValidationException when multiple errors occured
### Description

When there is more than one validation issue detected, the message describing the problem for each parameter is the same.

In my case, I have rules as `a > 5` and `b < 5` but I get:

```json
{
    "status_code": 400,
    "detail": "Validation failed for GET http://127.0.0.1:8000/?a=0&b=9",
    "extra": [
        {
            "message": "Expected `int` <= 4",
            "key": "a",
            "source": "query"
        },
        {
            "message": "Expected `int` <= 4",
            "key": "b",
            "source": "query"
        }
    ]
}
```

Single error (if only one parameter is invalid) is correctly displaying the message.


### URL to code causing the issue

_No response_

### MCVE

```python
from litestar import Litestar, get, Response
from litestar.params import Parameter
from typing import Annotated

@get("/")
async def default(
        a: Annotated[int, Parameter(gt=5)],
        b: Annotated[int, Parameter(lt=5)],
) -> Response:
    return Response(content=f'{a} {b}\n')

app = Litestar(route_handlers=[default])
```


### Steps to reproduce

```bash
Run the app and access the URL `http://127.0.0.1:8000/?a=0&b=9`.
```


### Screenshots

_No response_

### Logs

_No response_

### Litestar Version

Litestar 2.3.2 on Python 3.11.2


### Platform

- [X] Linux
- [ ] Mac
- [ ] Windows
- [ ] Other (Please specify in the description above)

<!-- POLAR PLEDGE BADGE START -->
---
> [!NOTE]  
> While we are open for sponsoring on [GitHub Sponsors](https://github.com/sponsors/litestar-org/) and 
> [OpenCollective](https://opencollective.com/litestar), we also utilize [Polar.sh](https://polar.sh/) to engage in pledge-based sponsorship.
>
> Check out all issues funded or available for funding [on our Polar.sh Litestar dashboard](https://polar.sh/litestar-org)
> * If you would like to see an issue prioritized, make a pledge towards it!
> * We receive the pledge once the issue is completed & verified
> * This, along with engagement in the community, helps us know which features are a priority to our users.

<a href="https://polar.sh/litestar-org/litestar/issues/2714">
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://polar.sh/api/github/litestar-org/litestar/issues/2714/pledge.svg?darkmode=1">
  <img alt="Fund with Polar" src="https://polar.sh/api/github/litestar-org/litestar/issues/2714/pledge.svg">
</picture>
</a>
<!-- POLAR PLEDGE BADGE END -->



Discussion:

Resolving patch:
diff --git a/litestar/_signature/model.py b/litestar/_signature/model.py
--- a/litestar/_signature/model.py
+++ b/litestar/_signature/model.py
@@ -198,7 +198,7 @@ def parse_values_from_connection_kwargs(cls, connection: ASGIConnection, **kwarg
             for field_name, exc in cls._collect_errors(deserializer=deserializer, **kwargs):  # type: ignore[assignment]
                 match = ERR_RE.search(str(exc))
                 keys = [field_name, str(match.group(1))] if match else [field_name]
-                message = cls._build_error_message(keys=keys, exc_msg=str(e), connection=connection)
+                message = cls._build_error_message(keys=keys, exc_msg=str(exc), connection=connection)
                 messages.append(message)
             raise cls._create_exception(messages=messages, connection=connection) from e
 


Test patch:
diff --git a/tests/unit/test_signature/test_validation.py b/tests/unit/test_signature/test_validation.py
--- a/tests/unit/test_signature/test_validation.py
+++ b/tests/unit/test_signature/test_validation.py
@@ -3,11 +3,12 @@
 
 import pytest
 from attr import define
-from typing_extensions import TypedDict
+from typing_extensions import Annotated, TypedDict
 
 from litestar import get, post
 from litestar._signature import SignatureModel
 from litestar.di import Provide
+from litestar.enums import ParamType
 from litestar.exceptions import ImproperlyConfiguredException, ValidationException
 from litestar.params import Dependency, Parameter
 from litestar.status_codes import HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
@@ -225,7 +226,7 @@ def test(
         assert data["extra"] == [
             {"message": "Expected `int`, got `str`", "key": "child.val", "source": "body"},
             {"message": "Expected `int`, got `str`", "key": "int_param", "source": "query"},
-            {"message": "Expected `int`, got `str`", "key": "length_param", "source": "query"},
+            {"message": "Expected `str` of length >= 2", "key": "length_param", "source": "query"},
             {"message": "Expected `int`, got `str`", "key": "int_header", "source": "header"},
             {"message": "Expected `int`, got `str`", "key": "int_cookie", "source": "cookie"},
         ]
@@ -270,7 +271,27 @@ def test(
         assert data["extra"] == [
             {"message": "Expected `int`, got `str`", "key": "child.val", "source": "body"},
             {"message": "Expected `int`, got `str`", "key": "int_param", "source": "query"},
-            {"message": "Expected `int`, got `str`", "key": "length_param", "source": "query"},
+            {"message": "Expected `str` of length >= 2", "key": "length_param", "source": "query"},
             {"message": "Expected `int`, got `str`", "key": "int_header", "source": "header"},
             {"message": "Expected `int`, got `str`", "key": "int_cookie", "source": "cookie"},
         ]
+
+
+def test_parse_values_from_connection_kwargs_with_multiple_errors() -> None:
+    def fn(a: Annotated[int, Parameter(gt=5)], b: Annotated[int, Parameter(lt=5)]) -> None:
+        pass
+
+    model = SignatureModel.create(
+        dependency_name_set=set(),
+        fn=fn,
+        data_dto=None,
+        parsed_signature=ParsedSignature.from_fn(fn, {}),
+        type_decoders=[],
+    )
+    with pytest.raises(ValidationException) as exc:
+        model.parse_values_from_connection_kwargs(connection=RequestFactory().get(), a=0, b=9)
+
+    assert exc.value.extra == [
+        {"message": "Expected `int` >= 6", "key": "a", "source": ParamType.QUERY},
+        {"message": "Expected `int` <= 4", "key": "b", "source": ParamType.QUERY},
+    ]