diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py
index ee0e24f6e86ae33..834e772713e98f2 100644
--- a/Lib/test/test_xmlrpc.py
+++ b/Lib/test/test_xmlrpc.py
@@ -252,6 +252,13 @@ def test_loads_unsupported(self):
'')
self.assertRaises(ResponseError, xmlrpclib.loads, data)
+ def test_loads_malformed_struct(self):
+ ResponseError = xmlrpclib.ResponseError
+ data = (''
+ 'k'
+ '')
+ self.assertRaises(ResponseError, xmlrpclib.loads, data)
+
def check_loads(self, s, value, **kwargs):
dump = '%s' % s
result, m = xmlrpclib.loads(dump, **kwargs)
diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py
index 84e4e4d11a7319e..b4065b3d7f3f280 100644
--- a/Lib/xmlrpc/client.py
+++ b/Lib/xmlrpc/client.py
@@ -756,6 +756,8 @@ def end_struct(self, data):
# map structs to Python dictionaries
dict = {}
items = self._stack[mark:]
+ if len(items) % 2:
+ raise ResponseError()
for i in range(0, len(items), 2):
dict[items[i]] = items[i+1]
self._stack[mark:] = [dict]
diff --git a/Misc/NEWS.d/next/Library/2026-07-16-12-00-00.gh-issue-153803.YbLNRy.rst b/Misc/NEWS.d/next/Library/2026-07-16-12-00-00.gh-issue-153803.YbLNRy.rst
new file mode 100644
index 000000000000000..08f54899cd1df2d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-16-12-00-00.gh-issue-153803.YbLNRy.rst
@@ -0,0 +1,2 @@
+Fix :func:`xmlrpc.client.loads` raising :exc:`IndexError` instead of
+``ResponseError`` for a malformed ````. Patch by tonghuaroot.