Jump to solution
Verify

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%.

Jump to Verify Open PR/Commit
@@ -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')
repro.py
$ 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) ...
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
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).
Production impact:
  • 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

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…”
@sydney-runkle · 2024-03-15 · source
“Unless I'm mistaken, this is the only remaining issue”
@mgorny · 2024-03-15 · source
“@mgorny, I think it's just different output. Let's make it conditional to pytest version :). Thanks!!”
@sydney-runkle · 2024-03-15 · source

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
signature.txt
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.txt
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

repro.py
$ 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

When NOT to use: Do not apply this fix if using a pytest version lower than 8.

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.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • Do not apply this fix if using a pytest version lower than 8.

Verify Fix

verify
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

VersionStatus
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.