The Fix
pip install pydantic==1.10.15
Based on closed pydantic/pydantic issue #8995 · PR/commit linked
Production note: Most teams hit this during upgrades or environment changes. Roll out with a canary and smoke critical endpoints (health, OpenAPI/docs) before 100%.
@@ -1344,20 +1344,20 @@ class Model(BaseModel):
@classmethod
def check_a(cls, v: Any):
- assert v == 'a', 'invalid a'
+ if v != 'a':
+ raise AssertionError('invalid a')
$ python -m pytest -Wdefault -vv
============================= test session starts ==============================
platform linux -- Python 3.11.8, pytest-8.1.1, pluggy-1.4.0 -- /tmp/pydantic/.venv/bin/python
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase(PosixPath('/tmp/pydantic/.hypothesis/examples'))
benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=True warmup_iterations=100000)
rootdir: /tmp/pydantic
configfile: pyproject.toml
testpaths: tests
plugins: hypothesis-6.99.5, xdist-3.5.0, benchmark-4.0.0, examples-0.0.10, mock-3.12.0, Faker-24.1.0
collecting ... collected 5002 items
[…]
============================================================== FAILURES ===============================================================
_________________________________________________ test_assert_raises_validation_error _________________________________________________
def test_assert_raises_validation_error():
class Model(BaseModel):
a: str
@field_validator('a')
@classmethod
def check_a(cls, v: Any):
assert v == 'a', 'invalid a'
return v
Model(a='a')
with pytest.raises(ValidationError) as exc_info:
Model(a='snap')
injected_by_pytest = "assert 'snap' == 'a'\n - a\n + snap"
assert exc_info.value.errors(include_url=False) == [
{
'ctx': {'error': HasRepr(repr(AssertionError("invalid a\nassert 'snap' == 'a'\n - a\n + snap")))},
'input': 'snap',
'loc': ('a',),
'msg': f'Assertion failed, invalid a\n{injected_by_pytest}',
'type': 'assertion_error',
}
]
E assert [{'type': 'assertion_error', 'loc': ('a',), 'msg': "Assertion failed, invalid a\nassert 'snap' == 'a'\n \n - a\n + snap", 'input': 'snap', 'ctx': {'error': AssertionError("invalid a\nassert 'snap' == 'a'\n \n - a\n + snap")}}] == [{'ctx': {'error': HasRepr('AssertionError("invalid a\\nassert \'snap\' == \'a\'\\n - a\\n + snap")')}, 'input': 'snap', 'loc': ('a',), 'msg': "Assertion failed, invalid a\nassert 'snap' == 'a'\n - a\n + snap", 'type': 'assertion_error'}]
E
E At index 0 diff: {'type': 'assertion_error', 'loc': ('a',), 'msg': "Assertion failed, invalid a\nassert 'snap' == 'a'\n \n - a\n + snap", 'input': 'snap', 'ctx': {'error': AssertionError("invalid a\nassert 'snap' == 'a'\n \n - a\n + snap")}} != {'ctx': {'error': HasRepr('AssertionError("invalid a\\nassert \'snap\' == \'a\'\\n - a\\n + snap")')}, 'input': 'snap', 'loc': ('a',), 'msg': "Assertion failed, invalid a\nassert 'snap' == 'a'\n - a\n + snap", 'type': 'assertion_error'}
E
E Full diff:
E [
E {
E 'ctx': {
E - 'error': HasRepr('AssertionError("invalid a\\nassert \'snap\' == \'a\'\\n - a\\n + snap")'),
E ? --------- - - - - - - --
E + 'error': AssertionError("invalid a\nassert 'snap' == 'a'\n \n - a\n + snap"),
E ? +++
E },
E 'input': 'snap',
E 'loc': (
E 'a',
E ),
E 'msg': 'Assertion failed, invalid a\n'
E
... (truncated) ...
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Upgrade to fixed release\npip install pydantic==1.10.15\nWhen NOT to use: Do not apply this fix if using a pytest version lower than 8.\n\n
Why This Fix Works in Production
- Trigger: `tests/test_validators.py::test_assert_raises_validation_error` fails with pytest 8
- Mechanism: The test fails due to different assertion output in pytest 8
- Why the fix works: Fixes the test `test_assert_raises_validation_error` to support different assertion output from pytest 8. (first fixed release: 1.10.15).
- If left unfixed, the same config can fail only in production (env differences), causing startup failures or partial feature outages.
Why This Breaks in Prod
- Shows up under Python 3.11.8 in real deployments (not just unit tests).
- The test fails due to different assertion output in pytest 8
- Production symptom (often without a traceback): `tests/test_validators.py::test_assert_raises_validation_error` fails with pytest 8
Proof / Evidence
- GitHub issue: #8995
- Fix PR: https://github.com/pydantic/pydantic/pull/9024
- First fixed release: 1.10.15
- Reproduced locally: No (not executed)
- Last verified: 2026-02-09
- Confidence: 0.85
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.38
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“@mgorny, Thanks for reporting this. Indeed, we'll probably have to fix up a few tests in order to move to pytest v8. I'll mark this…”
“Unless I'm mistaken, this is the only remaining issue”
“@mgorny, I think it's just different output. Let's make it conditional to pytest version :). Thanks!!”
Failure Signature (Search String)
- `tests/test_validators.py::test_assert_raises_validation_error` fails with pytest 8
- The following test failures with pytest 8 remained:
Copy-friendly signature
Failure Signature
-----------------
`tests/test_validators.py::test_assert_raises_validation_error` fails with pytest 8
The following test failures with pytest 8 remained:
Error Message
Signature-only (no traceback captured)
Error Message
-------------
`tests/test_validators.py::test_assert_raises_validation_error` fails with pytest 8
The following test failures with pytest 8 remained:
Minimal Reproduction
$ python -m pytest -Wdefault -vv
============================= test session starts ==============================
platform linux -- Python 3.11.8, pytest-8.1.1, pluggy-1.4.0 -- /tmp/pydantic/.venv/bin/python
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase(PosixPath('/tmp/pydantic/.hypothesis/examples'))
benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=True warmup_iterations=100000)
rootdir: /tmp/pydantic
configfile: pyproject.toml
testpaths: tests
plugins: hypothesis-6.99.5, xdist-3.5.0, benchmark-4.0.0, examples-0.0.10, mock-3.12.0, Faker-24.1.0
collecting ... collected 5002 items
[…]
============================================================== FAILURES ===============================================================
_________________________________________________ test_assert_raises_validation_error _________________________________________________
def test_assert_raises_validation_error():
class Model(BaseModel):
a: str
@field_validator('a')
@classmethod
def check_a(cls, v: Any):
assert v == 'a', 'invalid a'
return v
Model(a='a')
with pytest.raises(ValidationError) as exc_info:
Model(a='snap')
injected_by_pytest = "assert 'snap' == 'a'\n - a\n + snap"
assert exc_info.value.errors(include_url=False) == [
{
'ctx': {'error': HasRepr(repr(AssertionError("invalid a\nassert 'snap' == 'a'\n - a\n + snap")))},
'input': 'snap',
'loc': ('a',),
'msg': f'Assertion failed, invalid a\n{injected_by_pytest}',
'type': 'assertion_error',
}
]
E assert [{'type': 'assertion_error', 'loc': ('a',), 'msg': "Assertion failed, invalid a\nassert 'snap' == 'a'\n \n - a\n + snap", 'input': 'snap', 'ctx': {'error': AssertionError("invalid a\nassert 'snap' == 'a'\n \n - a\n + snap")}}] == [{'ctx': {'error': HasRepr('AssertionError("invalid a\\nassert \'snap\' == \'a\'\\n - a\\n + snap")')}, 'input': 'snap', 'loc': ('a',), 'msg': "Assertion failed, invalid a\nassert 'snap' == 'a'\n - a\n + snap", 'type': 'assertion_error'}]
E
E At index 0 diff: {'type': 'assertion_error', 'loc': ('a',), 'msg': "Assertion failed, invalid a\nassert 'snap' == 'a'\n \n - a\n + snap", 'input': 'snap', 'ctx': {'error': AssertionError("invalid a\nassert 'snap' == 'a'\n \n - a\n + snap")}} != {'ctx': {'error': HasRepr('AssertionError("invalid a\\nassert \'snap\' == \'a\'\\n - a\\n + snap")')}, 'input': 'snap', 'loc': ('a',), 'msg': "Assertion failed, invalid a\nassert 'snap' == 'a'\n - a\n + snap", 'type': 'assertion_error'}
E
E Full diff:
E [
E {
E 'ctx': {
E - 'error': HasRepr('AssertionError("invalid a\\nassert \'snap\' == \'a\'\\n - a\\n + snap")'),
E ? --------- - - - - - - --
E + 'error': AssertionError("invalid a\nassert 'snap' == 'a'\n \n - a\n + snap"),
E ? +++
E },
E 'input': 'snap',
E 'loc': (
E 'a',
E ),
E 'msg': 'Assertion failed, invalid a\n'
E
... (truncated) ...
Environment
- Python: 3.11.8
- Pydantic: 2
What Broke
Test failures lead to incorrect validation behavior in production environments.
Why It Broke
The test fails due to different assertion output in pytest 8
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
pip install pydantic==1.10.15
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Fix reference: https://github.com/pydantic/pydantic/pull/9024
First fixed release: 1.10.15
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- Do not apply this fix if using a pytest version lower than 8.
Verify Fix
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Did This Fix Work in Your Case?
Quick signal helps us prioritize which fixes to verify and improve.
Prevention
- Add a CI check that diffs key outputs after upgrades (OpenAPI schema snapshots, JSON payload shapes, CLI output).
- Upgrade behind a canary and run integration tests against the canary before 100% rollout.
Version Compatibility Table
| Version | Status |
|---|---|
| 1.10.15 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.