pytest.raises: get and check the error message (tested)
In pytest, catch the exception with with pytest.raises(ValueError) as excinfo: and read the message afterwards with str(excinfo.value), not str(excinfo). To check it in one line use match=, which is a regex search. Add a message to a plain assert with assert cond, "message".
Three related questions: how to read the message of an exception caught by pytest.raises, how to check it, and how to see the full message of a failed assert when the summary line cuts it off. Measured with pytest 9.1.1 on Python 3.13.5.
1. Get and check the exception message with pytest.raises
$ cat test_msg.py
import pytest
def parse_age(s):
n = int(s)
if n < 0:
raise ValueError(f"age must be >= 0, got {n}")
return n
def test_get_message():
with pytest.raises(ValueError) as excinfo:
parse_age("-3")
print("type: ", excinfo.type.__name__)
print("str: ", str(excinfo.value))
print("args: ", excinfo.value.args)
assert str(excinfo.value) == "age must be >= 0, got -3"
def test_match_is_a_search():
with pytest.raises(ValueError, match="got -3"): # partial: passes
parse_age("-3")
with pytest.raises(ValueError, match=r"^age must be >= 0, got -3$"):
parse_age("-3")
def test_str_of_excinfo_is_not_the_message():
with pytest.raises(ValueError) as excinfo:
parse_age("abc")
print("str(excinfo): ", str(excinfo)[:60])
print("str(excinfo.value):", str(excinfo.value))
assert "abc" in str(excinfo)
$ pytest -q -s -p no:cacheprovider test_msg.py; echo "exit $?"
type: ValueError
str: age must be >= 0, got -3
args: ('age must be >= 0, got -3',)
..str(excinfo): <ExceptionInfo ValueError("invalid literal for int() with ba
str(excinfo.value): invalid literal for int() with base 10: 'abc'
.
3 passed in 0.00s
exit 0
with pytest.raises(...) as excinfo gives you an ExceptionInfo. The exception itself is excinfo.value; its message is str(excinfo.value) (or excinfo.value.args), and the class is excinfo.type. Use these after the with block. str(excinfo) is not the message: it is a repr like <ExceptionInfo ValueError(...) tblen=...>, so an in check against it can pass by accident. match= is a re.search, so a fragment is enough; anchor with ^...$ for an exact match, and wrap literal text in re.escape() when it contains ( ) . [ ] + (see pytest Failed: DID NOT RAISE).
2. A custom message for a plain assert
$ cat test_assert.py
def test_custom_message():
items = ["a", "b"]
assert len(items) == 3, f"expected 3 items, got {items}"
$ pytest -q -p no:cacheprovider test_assert.py; echo "exit $?"
F [100%]
=================================== FAILURES ===================================
_____________________________ test_custom_message ______________________________
def test_custom_message():
items = ["a", "b"]
> assert len(items) == 3, f"expected 3 items, got {items}"
E AssertionError: expected 3 items, got ['a', 'b']
E assert 2 == 3
E + where 2 = len(['a', 'b'])
test_assert.py:3: AssertionError
=========================== short test summary info ============================
FAILED test_assert.py::test_custom_message - AssertionError: expected 3 items...
1 failed in 0.01s
exit 1
The text after the comma becomes the AssertionError message, and pytest still shows its own introspection (assert 2 == 3, where 2 = len([...])) below it. Exit code 1 means tests failed.
3. The short summary truncates the message: see it in full
$ pytest -q -p no:cacheprovider --tb=no test_assert.py | tail -2
FAILED test_assert.py::test_custom_message - AssertionError: expected 3 items...
1 failed in 0.00s
$ pytest -vv -p no:cacheprovider --tb=no test_assert.py | grep FAILED
test_assert.py::test_custom_message FAILED [100%]
FAILED test_assert.py::test_custom_message - AssertionError: expected 3 items, got ['a', 'b']
$ pytest -q -p no:cacheprovider --tb=line test_assert.py | grep -A1 AssertionError | head -2
E AssertionError: expected 3 items, got ['a', 'b']
assert 2 == 3
In the default short test summary the message ends in .... -vv prints the whole message on the FAILED line; --tb=line or the default traceback output also show it in full.
Related: pytest.fail with a message vs xfail, pytest error vs failure, assert log messages with caplog.
Frequently asked questions
How do I get the error message from pytest.raises?
Use with pytest.raises(SomeError) as excinfo: ... and then str(excinfo.value) after the with block. excinfo.type is the class and excinfo.value.args the arguments.
How do I check the exception message in pytest?
pytest.raises(SomeError, match="fragment") does a re.search on str(exception). Anchor with ^...$ for an exact match and use re.escape for literal text with special characters.
How do I see the full assert message in pytest?
The short summary truncates it with ...; run pytest -vv or look at the traceback section (or --tb=line) for the full message.
Written with AI assistance. Measured on 2026-10-23 with pytest 9.1.1 on Python 3.13.5 in a clean virtualenv. Each block was run verbatim and the output pasted unedited. PlainHeaders is our extension; pytest is free.