Skip to content

serialize() crashes with TypeError when panel data contains dicts with non-string keys #2317

Description

@bleadof

Environment

  • Django Debug Toolbar: 6.2.0 (also reproduced on 6.1.0)
  • Python: 3.12
  • Django: 5.2

Error

File "debug_toolbar/store.py", in save_panel
    cls._request_store[request_id][panel_id] = serialize(data)
File "debug_toolbar/store.py", in serialize
    return json.dumps(data, cls=DebugToolbarJSONEncoder)
TypeError: keys must be str, int, float, bool or None, not tuple

Root cause?

DebugToolbarJSONEncoder.default() seems to handle non-serializable values via force_str, but Python's JSON C encoder raises TypeError for non-string dict keys before default() is ever invoked. I guess it's a known issue since store.py already has a comment describing this failure?

Affected panels

CachePanel - triggered when a cached value is a dict with non-string keys:

from uuid import UUID
from django.core.cache import cache

cache.set("my_key", {
    (UUID("aaaaaaaa-0000-0000-0000-000000000001"), UUID("bbbbbbbb-0000-0000-0000-000000000002")): {"value": 1},
    (UUID("dddddddd-0000-0000-0000-000000000004"), UUID("eeeeeeee-0000-0000-0000-000000000005")): {"value": 2},
}, timeout=300)

_store_call_info captures the raw args tuple (including the dict value) into self.calls. When generate_stats serializes self.calls, json.dumps raises on the tuple keys inside that dict.

RequestPanel - triggered when a session value is a dict with non-string keys:

request.session["lookup"] = {(1, 2): "foo", (3, 4): "bar"}

sanitize_and_sort_request_vars wraps the session in {"list": [...]} but passes dict values through unchanged, so the nested dict with tuple keys reaches serialize() and crashes.

Workaround

Exclude the affected panels in DEBUG_TOOLBAR_PANELS in Django settings.py:

DEBUG_TOOLBAR_PANELS = [
    "debug_toolbar.panels.history.HistoryPanel",
    "debug_toolbar.panels.versions.VersionsPanel",
    "debug_toolbar.panels.timer.TimerPanel",
    "debug_toolbar.panels.settings.SettingsPanel",
    "debug_toolbar.panels.headers.HeadersPanel",
    # "debug_toolbar.panels.request.RequestPanel",
    "debug_toolbar.panels.sql.SQLPanel",
    "debug_toolbar.panels.staticfiles.StaticFilesPanel",
    "debug_toolbar.panels.templates.TemplatesPanel",
    "debug_toolbar.panels.alerts.AlertsPanel",
    # "debug_toolbar.panels.cache.CachePanel",
    "debug_toolbar.panels.signals.SignalsPanel",
    "debug_toolbar.panels.logging.LoggingPanel",
    "debug_toolbar.panels.redirects.RedirectsPanel",
    "debug_toolbar.panels.profiling.ProfilingPanel",
]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions