diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 899947c1f8e0d74..2689264a1b00e51 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1324,6 +1324,11 @@ def test_parse_error_after_chunk_boundary(self):
ET.fromstring('%s<' % ('x' * size))
self.assertEqual(cm.exception.position, (1, size + 4))
+ def test_parse_error_msg_is_string(self):
+ with self.assertRaises(ET.ParseError) as cm:
+ ET.XML("<")
+ self.assertIsInstance(cm.exception.msg, str)
+ self.assertEqual(cm.exception.msg, "unclosed token: line 1, column 0")
@support.subTests('sample,exception', [
(b' \xa1', UnicodeDecodeError), # crashed
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index 0cd04ead801600e..3a50b1329bde3e9 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -1709,7 +1709,7 @@ def handler(pi_target, data, event=event_name, append=append,
raise ValueError("unknown event %r" % event_name)
def _raiseerror(self, value):
- err = ParseError(value)
+ err = ParseError(str(value))
err.code = value.code
err.position = value.lineno, value.offset
raise err
diff --git a/Misc/NEWS.d/next/Library/2026-09-26-09-44-59.gh-issue-158166.lVGCsI.rst b/Misc/NEWS.d/next/Library/2026-09-26-09-44-59.gh-issue-158166.lVGCsI.rst
new file mode 100644
index 000000000000000..56f76dec1575817
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-09-26-09-44-59.gh-issue-158166.lVGCsI.rst
@@ -0,0 +1 @@
+Make pure-Python ElementTree ParseError first argument always a str.