From 203f8cd920be9503613b7f7fb5df5e204ceb9a98 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 02:55:03 +0000 Subject: [PATCH] fix: json_serial returns bytes instead of str for non-UTF-8 binary values When json_serial() receives bytes that cannot be decoded as UTF-8, the fallback path calls base64.b64encode(), which returns bytes, not str. Returning bytes from a json.JSONEncoder default hook causes an immediate TypeError ("Object of type bytes is not JSON serializable") that defeats the entire purpose of the fallback. Decode the base64 result to an ASCII string before returning so that the value can always be embedded in a JSON document. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_012acaiEt2JyZdUxjQndUWQL --- pygeoapi/util.py | 2 +- tests/other/test_util.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pygeoapi/util.py b/pygeoapi/util.py index b60e187a08..2accb96c49 100644 --- a/pygeoapi/util.py +++ b/pygeoapi/util.py @@ -423,7 +423,7 @@ def json_serial(obj: Any) -> str: return obj.decode('utf-8') except UnicodeDecodeError: LOGGER.debug('Returning as base64 encoded JSON object') - return base64.b64encode(obj) + return base64.b64encode(obj).decode('ascii') elif isinstance(obj, Decimal): return float(obj) elif type(obj).__name__ in ['int32', 'int64']: diff --git a/tests/other/test_util.py b/tests/other/test_util.py index 7cb321019d..e857e6dad3 100644 --- a/tests/other/test_util.py +++ b/tests/other/test_util.py @@ -166,6 +166,20 @@ def test_json_serial(): d = uuid.UUID('12345678-1234-5678-1234-567812345678') assert util.json_serial(d) == '12345678-1234-5678-1234-567812345678' + # Valid UTF-8 bytes round-trip as a plain string + assert util.json_serial(b'hello') == 'hello' + + # Non-UTF-8 bytes must produce a base64 *str* (not bytes), so that the + # result can be serialised to JSON without a TypeError. + raw = b'\x80\x81\x82' + result = util.json_serial(raw) + assert isinstance(result, str), "json_serial must return str, not bytes" + import base64 as _b64 + assert result == _b64.b64encode(raw).decode('ascii') + import json as _json + # Must be embeddable in a JSON document without raising + _json.dumps({'data': result}) + with pytest.raises(TypeError): util.json_serial('foo')