From 68ce658f5d651c62bf0b92da5bdb080ce63cd002 Mon Sep 17 00:00:00 2001 From: Benoit Chesneau Date: Wed, 11 Feb 2026 23:39:53 +0100 Subject: [PATCH] fix(dirty): convert dict int keys to strings in TLV encoder JSON serializes all dict keys as strings, so for compatibility the TLV encoder should do the same. This fixes an error when tasks return dicts with integer keys (e.g., aggregation results grouped by numeric ID). --- gunicorn/dirty/tlv.py | 6 ++---- tests/test_dirty_tlv.py | 13 +++++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/gunicorn/dirty/tlv.py b/gunicorn/dirty/tlv.py index 5682b0c6..e0b1e2f4 100644 --- a/gunicorn/dirty/tlv.py +++ b/gunicorn/dirty/tlv.py @@ -113,11 +113,9 @@ class TLVEncoder: ) parts = [bytes([TYPE_DICT]), struct.pack(">I", len(value))] for k, v in value.items(): - # Keys must be strings + # Convert keys to strings (like JSON) if not isinstance(k, str): - raise DirtyProtocolError( - f"Dict keys must be strings, got {type(k).__name__}" - ) + k = str(k) parts.append(TLVEncoder.encode(k)) parts.append(TLVEncoder.encode(v)) return b"".join(parts) diff --git a/tests/test_dirty_tlv.py b/tests/test_dirty_tlv.py index 87727203..c36b839a 100644 --- a/tests/test_dirty_tlv.py +++ b/tests/test_dirty_tlv.py @@ -307,12 +307,13 @@ class TestTLVEncoderDict: value, offset = TLVEncoder.decode(encoded, 0) assert value == data - def test_encode_dict_non_string_key(self): - """Test that non-string keys raise error.""" - data = {1: "value"} - with pytest.raises(DirtyProtocolError) as exc_info: - TLVEncoder.encode(data) - assert "keys must be strings" in str(exc_info.value).lower() + def test_encode_dict_non_string_key_converted(self): + """Test that non-string keys are converted to strings (like JSON).""" + data = {1: "value", 2: "other"} + encoded = TLVEncoder.encode(data) + decoded, _ = TLVEncoder.decode(encoded, 0) + # Keys should be converted to strings + assert decoded == {"1": "value", "2": "other"} class TestTLVEncoderComplexStructures: