From cb7113199b00e306ee1454759623c40b7ddc97ac Mon Sep 17 00:00:00 2001 From: jm Date: Sun, 16 Aug 2026 16:29:09 +0200 Subject: [PATCH] fix(client): return empty bundles on 404 instead of crashing get_bundles() subscripted the None that fetch_resource returns on any non-200 response, so an item deleted since the cache was built (404) raised "'NoneType' object is not subscriptable" during a bitstream export - a scary CRITICAL line for what is really just "this item is gone". Record the failing response as _last_err in fetch_resource so callers can tell a gone resource (404) from a transient 5xx, then in get_bundles treat a 404 as a clean empty result. Any other failure still falls through and surfaces to the caller, so it keeps its retry and failure counting. Co-Authored-By: Claude Opus 4.8 --- dspace_rest_client/client.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dspace_rest_client/client.py b/dspace_rest_client/client.py index 0115557..e2058b9 100644 --- a/dspace_rest_client/client.py +++ b/dspace_rest_client/client.py @@ -475,6 +475,9 @@ def fetch_resource(self, url, params=None): """ r = self.api_get(url, params, None) if r.status_code != 200: + # record the failing response so callers can tell a 404 (the + # resource is gone) from a transient 5xx before we drop the body + self._last_err = r _logger.error(f'Error encountered fetching resource: {r.text}') return None # ValueError / JSON handling moved to static method @@ -698,6 +701,12 @@ def get_bundles(self, parent=None, uuid=None, page=0, size=20, sort=None): if sort is not None: params['sort'] = sort r_json = self.fetch_resource(url, params=params) + if r_json is None and getattr(self._last_err, 'status_code', None) == 404: + # the item (or bundle) no longer exists - a deleted item simply has + # no bundles, which is a clean empty result, not a crash. any other + # failure falls through and still surfaces to the caller. + _logger.info(f'No bundles: resource not found (404) [{url}]') + return bundles try: if single_result: bundles.append(Bundle(r_json))