Skip to content

to_builtins leaks the field objects of array_like=True structs (0.21.1) #1175

Closed

Description

@peymannaderi10

msgspec.to_builtins on a struct that contains an array_like=True struct never releases the field objects of the array-like struct: every call leaks them, even when the result is discarded. Converting through msgspec.json.decode(msgspec.json.encode(obj)) does not leak.

Environment: msgspec 0.21.1 (PyPI wheel), CPython 3.11, reproduced on Linux x86_64 and Windows 11.

Minimal reproduction:

import tracemalloc
import msgspec


class Box(msgspec.Struct, array_like=True):
    x1: float
    y1: float
    x2: float
    y2: float


class Row(msgspec.Struct):
    box: Box


def run(n: int, json_path: bool = False) -> int:
    row = Row(Box(1.5, 2.5, 3.5, 4.5))
    tracemalloc.start()
    for _ in range(n):
        obj = msgspec.msgpack.decode(msgspec.msgpack.encode(row), type=Row)
        if json_path:
            msgspec.json.decode(msgspec.json.encode(obj))
        else:
            msgspec.to_builtins(obj)
    cur, _ = tracemalloc.get_traced_memory()
    tracemalloc.stop()
    return cur


print("to_builtins", run(10_000), run(100_000))
print("json path  ", run(10_000, True), run(100_000, True))

Output on 0.21.1:

to_builtins 960904 9600136
json path   380 136

Traced memory scales linearly with the number of to_builtins calls (about 4 floats × 24 B per call — the four fields of Box; tracemalloc attributes them to the decode line that created them). The JSON round-trip stays flat. Without array_like=True on Box there is no growth either, so it looks like a missing DECREF on the array-like path in to_builtins.

Found in a 24 h soak of a service that converted ~30 messages/s with to_builtins: RSS grew ≈ 50 MB/h until the call was replaced.

Activity

  1. added a commit that references this issue on Sep 10, 2026
    ccbeca4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions