Skip to content

fix: keep TTree branch lookup indices valid when a generated counter collides - #1698

Draft
ariostas wants to merge 1 commit into
scikit-hep:mainfrom
ariostas:fix-cascadetree-counter-lookup
Draft

fix: keep TTree branch lookup indices valid when a generated counter collides#1698
ariostas wants to merge 1 commit into
scikit-hep:mainfrom
ariostas:fix-cascadetree-counter-lookup

Conversation

@ariostas

@ariostas ariostas commented Aug 5, 2026

Copy link
Copy Markdown
Member

🤖 AI text below 🤖

Addresses finding 1 of "PR 5" in #1688.

Tree._branch_lookup maps a branch name to its index in Tree._branch_data. When a jagged branch's generated counter name collides with a branch that was already declared, the colliding datum was removed with del:

https://github.com/scikit-hep/uproot5/blob/main/src/uproot/writing/_cascadetree.py#L203-L207

which shifts every later datum down by one, while _branch_lookup keeps pointing at the old indices.

f.mktree("t", {"nx": np.dtype("int32"), "y": np.dtype("float64"), "x": <jagged>})
# _branch_lookup == {'nx': 1, 'y': 1, 'x': 2}

y aliases the generated counter, and extending the tree fails.

Replaces the datum in place instead. That also keeps the counter ahead of the jagged branch it counts, since a colliding name must have been declared before the branch that generates it.

Note this needs mktree to reproduce: since v5.7.0 dict assignment produces an RNTuple, which does not go through this code.

Tests

tests/test_1688_cascadetree_counter_lookup.py: the lookup invariant (every name resolves to the datum carrying that name), a write/read round trip for the colliding schema, the existing "provided both as an explicit array and generated as a counter" error still firing when they disagree, and a non-colliding schema as a control. 2 of the 4 fail on main.

Full suite passes locally (1027 passed, 90 skipped).

Tree._branch_lookup maps a branch name to its index in Tree._branch_data. When
a jagged branch's generated counter name matched a branch that had already been
declared, the colliding datum was removed with 'del self._branch_data[...]',
which shifts every later datum down by one while _branch_lookup keeps pointing
at the old indices.

mktree with scalar 'nx', scalar 'y' and jagged 'x' produced the lookup
{'nx': 1, 'y': 1, 'x': 2}: 'y' aliased the generated counter, and extending the
tree failed. Replace the datum in place instead, which also keeps the counter
ahead of the jagged branch it counts.

Assisted-by: claude-code:claude-opus-5[1m]
@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
1279 1 1278 24
View the top 1 failed test(s) by shortest run time
tests/test_1120_check_decompression_executor_pass_for_dask.py::test_decompression_executor_for_dask
Stack Traces | 0.066s run time
x = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>
buffer_callback = <function pickle_dumps.<locals>.buffer_callback at 0x14699c7e4fe0>
protocol = None

    def dumps(x, *, buffer_callback=None, protocol=HIGHEST_PROTOCOL):
        """Manage between cloudpickle and pickle
    
        1.  Try pickle
        2.  If it is short then check if it contains __main__
        3.  If it is long, then first check type, then check __main__
        """
        buffers = []
        dump_kwargs = {"protocol": protocol or HIGHEST_PROTOCOL}
        if dump_kwargs["protocol"] >= 5 and buffer_callback is not None:
            dump_kwargs["buffer_callback"] = buffers.append
        try:
            try:
>               result = pickle.dumps(x, **dump_kwargs)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: cannot pickle '_thread._local' object

buffer_callback = <function pickle_dumps.<locals>.buffer_callback at 0x14699c7e4fe0>
buffers    = [<pickle.PickleBuffer object at 0x14699c749ec0>,
 <pickle.PickleBuffer object at 0x14699c749f40>,
 <pickle.PickleBuffer object at 0x14699c749fc0>,
 <pickle.PickleBuffer object at 0x14699c74a040>,
 <pickle.PickleBuffer object at 0x14699c74a0c0>,
 <pickle.PickleBuffer object at 0x14699c74a140>,
 <pickle.PickleBuffer object at 0x14699c74a1c0>,
 <pickle.PickleBuffer object at 0x14699c74a240>,
 <pickle.PickleBuffer object at 0x14699c74a2c0>,
 <pickle.PickleBuffer object at 0x14699c74a3c0>,
 <pickle.PickleBuffer object at 0x14699c74a440>,
 <pickle.PickleBuffer object at 0x14699c74a4c0>,
 <pickle.PickleBuffer object at 0x14699c74a540>,
 <pickle.PickleBuffer object at 0x14699c74a5c0>,
 <pickle.PickleBuffer object at 0x14699c74a640>,
 <pickle.PickleBuffer object at 0x14699c74a6c0>,
 <pickle.PickleBuffer object at 0x14699c74a740>,
 <pickle.PickleBuffer object at 0x14699c74a340>,
 <pickle.PickleBuffer object at 0x14699c74a7c0>,
 <pickle.PickleBuffer object at 0x14699c74a840>,
 <pickle.PickleBuffer object at 0x14699c74a8c0>,
 <pickle.PickleBuffer object at 0x14699c74a940>,
 <pickle.PickleBuffer object at 0x14699c74a9c0>,
 <pickle.PickleBuffer object at 0x14699c74aa40>,
 <pickle.PickleBuffer object at 0x14699c74aac0>,
 <pickle.PickleBuffer object at 0x14699c74ab40>,
 <pickle.PickleBuffer object at 0x14699c74abc0>,
 <pickle.PickleBuffer object at 0x14699c74ac40>,
 <pickle.PickleBuffer object at 0x14699c74acc0>,
 <pickle.PickleBuffer object at 0x14699c74ad40>,
 <pickle.PickleBuffer object at 0x14699c74adc0>,
 <pickle.PickleBuffer object at 0x14699c74ae40>,
 <pickle.PickleBuffer object at 0x14699c74aec0>,
 <pickle.PickleBuffer object at 0x14699c74af40>,
 <pickle.PickleBuffer object at 0x14699c74afc0>,
 <pickle.PickleBuffer object at 0x14699c74b040>,
 <pickle.PickleBuffer object at 0x14699c74b0c0>,
 <pickle.PickleBuffer object at 0x14699c74b140>,
 <pickle.PickleBuffer object at 0x14699c74b1c0>,
 <pickle.PickleBuffer object at 0x14699c74b240>,
 <pickle.PickleBuffer object at 0x14699c74b2c0>,
 <pickle.PickleBuffer object at 0x14699c74b340>,
 <pickle.PickleBuffer object at 0x14699c74b3c0>,
 <pickle.PickleBuffer object at 0x14699c74b440>,
 <pickle.PickleBuffer object at 0x14699c74b4c0>,
 <pickle.PickleBuffer object at 0x14699c74b540>,
 <pickle.PickleBuffer object at 0x14699c74b5c0>,
 <pickle.PickleBuffer object at 0x14699c74b640>,
 <pickle.PickleBuffer object at 0x14699c74b6c0>,
 <pickle.PickleBuffer object at 0x14699c74b740>,
 <pickle.PickleBuffer object at 0x14699c74b7c0>,
 <pickle.PickleBuffer object at 0x14699c74b840>,
 <pickle.PickleBuffer object at 0x14699c74b8c0>,
 <pickle.PickleBuffer object at 0x14699c74b940>,
 <pickle.PickleBuffer object at 0x14699c74b9c0>,
 <pickle.PickleBuffer object at 0x14699c74ba40>,
 <pickle.PickleBuffer object at 0x14699c74bac0>,
 <pickle.PickleBuffer object at 0x14699c74bb40>,
 <pickle.PickleBuffer object at 0x14699c74bbc0>,
 <pickle.PickleBuffer object at 0x14699c74bc40>,
 <pickle.PickleBuffer object at 0x14699c74bcc0>,
 <pickle.PickleBuffer object at 0x14699c74bd40>,
 <pickle.PickleBuffer object at 0x14699c74bdc0>,
 <pickle.PickleBuffer object at 0x14699c74be40>,
 <pickle.PickleBuffer object at 0x14699c74bec0>,
 <pickle.PickleBuffer object at 0x14699c74bf40>,
 <pickle.PickleBuffer object at 0x14699c75c040>,
 <pickle.PickleBuffer object at 0x14699c75c0c0>,
 <pickle.PickleBuffer object at 0x14699c75c140>,
 <pickle.PickleBuffer object at 0x14699c75c1c0>,
 <pickle.PickleBuffer object at 0x14699c75c240>,
 <pickle.PickleBuffer object at 0x14699c75c2c0>,
 <pickle.PickleBuffer object at 0x14699c75c340>,
 <pickle.PickleBuffer object at 0x14699c75c3c0>,
 <pickle.PickleBuffer object at 0x14699c75c440>,
 <pickle.PickleBuffer object at 0x14699c75c4c0>,
 <pickle.PickleBuffer object at 0x14699c75c540>,
 <pickle.PickleBuffer object at 0x14699c75c5c0>,
 <pickle.PickleBuffer object at 0x14699c75c640>,
 <pickle.PickleBuffer object at 0x14699c75c6c0>,
 <pickle.PickleBuffer object at 0x14699c75c740>,
 <pickle.PickleBuffer object at 0x14699c75c7c0>,
 <pickle.PickleBuffer object at 0x14699c75c840>,
 <pickle.PickleBuffer object at 0x14699c75c8c0>,
 <pickle.PickleBuffer object at 0x14699c75c940>,
 <pickle.PickleBuffer object at 0x14699c75c9c0>,
 <pickle.PickleBuffer object at 0x14699c75ca40>,
 <pickle.PickleBuffer object at 0x14699c75cac0>,
 <pickle.PickleBuffer object at 0x14699c75cb40>,
 <pickle.PickleBuffer object at 0x14699c75cbc0>,
 <pickle.PickleBuffer object at 0x14699c75cc40>,
 <pickle.PickleBuffer object at 0x14699c75ccc0>,
 <pickle.PickleBuffer object at 0x14699c75cd40>,
 <pickle.PickleBuffer object at 0x14699c75cdc0>,
 <pickle.PickleBuffer object at 0x14699c75ce40>,
 <pickle.PickleBuffer object at 0x14699c75cec0>,
 <pickle.PickleBuffer object at 0x14699c75cf40>,
 <pickle.PickleBuffer object at 0x14699c75cfc0>,
 <pickle.PickleBuffer object at 0x14699c75d040>,
 <pickle.PickleBuffer object at 0x14699c75d0c0>,
 <pickle.PickleBuffer object at 0x14699c75d140>,
 <pickle.PickleBuffer object at 0x14699c75d1c0>,
 <pickle.PickleBuffer object at 0x14699c75d240>,
 <pickle.PickleBuffer object at 0x14699c75d2c0>,
 <pickle.PickleBuffer object at 0x14699c75d340>]
dump_kwargs = {'buffer_callback': <built-in method append of list object at 0x146946423540>,
 'protocol': 5}
f          = <_io.BytesIO object at 0x146945c19080>
pickler    = <distributed.protocol.pickle._DaskPickler object at 0x146b1d82ae10>
protocol   = None
x          = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>

.../test-env/lib/python3.13.../distributed/protocol/pickle.py:60: TypeError

During handling of the above exception, another exception occurred:

x = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>
buffer_callback = <function pickle_dumps.<locals>.buffer_callback at 0x14699c7e4fe0>
protocol = None

    def dumps(x, *, buffer_callback=None, protocol=HIGHEST_PROTOCOL):
        """Manage between cloudpickle and pickle
    
        1.  Try pickle
        2.  If it is short then check if it contains __main__
        3.  If it is long, then first check type, then check __main__
        """
        buffers = []
        dump_kwargs = {"protocol": protocol or HIGHEST_PROTOCOL}
        if dump_kwargs["protocol"] >= 5 and buffer_callback is not None:
            dump_kwargs["buffer_callback"] = buffers.append
        try:
            try:
                result = pickle.dumps(x, **dump_kwargs)
            except Exception:
                f = io.BytesIO()
                pickler = _DaskPickler(f, **dump_kwargs)
                buffers.clear()
>               pickler.dump(x)
E               TypeError: cannot pickle '_thread._local' object

buffer_callback = <function pickle_dumps.<locals>.buffer_callback at 0x14699c7e4fe0>
buffers    = [<pickle.PickleBuffer object at 0x14699c749ec0>,
 <pickle.PickleBuffer object at 0x14699c749f40>,
 <pickle.PickleBuffer object at 0x14699c749fc0>,
 <pickle.PickleBuffer object at 0x14699c74a040>,
 <pickle.PickleBuffer object at 0x14699c74a0c0>,
 <pickle.PickleBuffer object at 0x14699c74a140>,
 <pickle.PickleBuffer object at 0x14699c74a1c0>,
 <pickle.PickleBuffer object at 0x14699c74a240>,
 <pickle.PickleBuffer object at 0x14699c74a2c0>,
 <pickle.PickleBuffer object at 0x14699c74a3c0>,
 <pickle.PickleBuffer object at 0x14699c74a440>,
 <pickle.PickleBuffer object at 0x14699c74a4c0>,
 <pickle.PickleBuffer object at 0x14699c74a540>,
 <pickle.PickleBuffer object at 0x14699c74a5c0>,
 <pickle.PickleBuffer object at 0x14699c74a640>,
 <pickle.PickleBuffer object at 0x14699c74a6c0>,
 <pickle.PickleBuffer object at 0x14699c74a740>,
 <pickle.PickleBuffer object at 0x14699c74a340>,
 <pickle.PickleBuffer object at 0x14699c74a7c0>,
 <pickle.PickleBuffer object at 0x14699c74a840>,
 <pickle.PickleBuffer object at 0x14699c74a8c0>,
 <pickle.PickleBuffer object at 0x14699c74a940>,
 <pickle.PickleBuffer object at 0x14699c74a9c0>,
 <pickle.PickleBuffer object at 0x14699c74aa40>,
 <pickle.PickleBuffer object at 0x14699c74aac0>,
 <pickle.PickleBuffer object at 0x14699c74ab40>,
 <pickle.PickleBuffer object at 0x14699c74abc0>,
 <pickle.PickleBuffer object at 0x14699c74ac40>,
 <pickle.PickleBuffer object at 0x14699c74acc0>,
 <pickle.PickleBuffer object at 0x14699c74ad40>,
 <pickle.PickleBuffer object at 0x14699c74adc0>,
 <pickle.PickleBuffer object at 0x14699c74ae40>,
 <pickle.PickleBuffer object at 0x14699c74aec0>,
 <pickle.PickleBuffer object at 0x14699c74af40>,
 <pickle.PickleBuffer object at 0x14699c74afc0>,
 <pickle.PickleBuffer object at 0x14699c74b040>,
 <pickle.PickleBuffer object at 0x14699c74b0c0>,
 <pickle.PickleBuffer object at 0x14699c74b140>,
 <pickle.PickleBuffer object at 0x14699c74b1c0>,
 <pickle.PickleBuffer object at 0x14699c74b240>,
 <pickle.PickleBuffer object at 0x14699c74b2c0>,
 <pickle.PickleBuffer object at 0x14699c74b340>,
 <pickle.PickleBuffer object at 0x14699c74b3c0>,
 <pickle.PickleBuffer object at 0x14699c74b440>,
 <pickle.PickleBuffer object at 0x14699c74b4c0>,
 <pickle.PickleBuffer object at 0x14699c74b540>,
 <pickle.PickleBuffer object at 0x14699c74b5c0>,
 <pickle.PickleBuffer object at 0x14699c74b640>,
 <pickle.PickleBuffer object at 0x14699c74b6c0>,
 <pickle.PickleBuffer object at 0x14699c74b740>,
 <pickle.PickleBuffer object at 0x14699c74b7c0>,
 <pickle.PickleBuffer object at 0x14699c74b840>,
 <pickle.PickleBuffer object at 0x14699c74b8c0>,
 <pickle.PickleBuffer object at 0x14699c74b940>,
 <pickle.PickleBuffer object at 0x14699c74b9c0>,
 <pickle.PickleBuffer object at 0x14699c74ba40>,
 <pickle.PickleBuffer object at 0x14699c74bac0>,
 <pickle.PickleBuffer object at 0x14699c74bb40>,
 <pickle.PickleBuffer object at 0x14699c74bbc0>,
 <pickle.PickleBuffer object at 0x14699c74bc40>,
 <pickle.PickleBuffer object at 0x14699c74bcc0>,
 <pickle.PickleBuffer object at 0x14699c74bd40>,
 <pickle.PickleBuffer object at 0x14699c74bdc0>,
 <pickle.PickleBuffer object at 0x14699c74be40>,
 <pickle.PickleBuffer object at 0x14699c74bec0>,
 <pickle.PickleBuffer object at 0x14699c74bf40>,
 <pickle.PickleBuffer object at 0x14699c75c040>,
 <pickle.PickleBuffer object at 0x14699c75c0c0>,
 <pickle.PickleBuffer object at 0x14699c75c140>,
 <pickle.PickleBuffer object at 0x14699c75c1c0>,
 <pickle.PickleBuffer object at 0x14699c75c240>,
 <pickle.PickleBuffer object at 0x14699c75c2c0>,
 <pickle.PickleBuffer object at 0x14699c75c340>,
 <pickle.PickleBuffer object at 0x14699c75c3c0>,
 <pickle.PickleBuffer object at 0x14699c75c440>,
 <pickle.PickleBuffer object at 0x14699c75c4c0>,
 <pickle.PickleBuffer object at 0x14699c75c540>,
 <pickle.PickleBuffer object at 0x14699c75c5c0>,
 <pickle.PickleBuffer object at 0x14699c75c640>,
 <pickle.PickleBuffer object at 0x14699c75c6c0>,
 <pickle.PickleBuffer object at 0x14699c75c740>,
 <pickle.PickleBuffer object at 0x14699c75c7c0>,
 <pickle.PickleBuffer object at 0x14699c75c840>,
 <pickle.PickleBuffer object at 0x14699c75c8c0>,
 <pickle.PickleBuffer object at 0x14699c75c940>,
 <pickle.PickleBuffer object at 0x14699c75c9c0>,
 <pickle.PickleBuffer object at 0x14699c75ca40>,
 <pickle.PickleBuffer object at 0x14699c75cac0>,
 <pickle.PickleBuffer object at 0x14699c75cb40>,
 <pickle.PickleBuffer object at 0x14699c75cbc0>,
 <pickle.PickleBuffer object at 0x14699c75cc40>,
 <pickle.PickleBuffer object at 0x14699c75ccc0>,
 <pickle.PickleBuffer object at 0x14699c75cd40>,
 <pickle.PickleBuffer object at 0x14699c75cdc0>,
 <pickle.PickleBuffer object at 0x14699c75ce40>,
 <pickle.PickleBuffer object at 0x14699c75cec0>,
 <pickle.PickleBuffer object at 0x14699c75cf40>,
 <pickle.PickleBuffer object at 0x14699c75cfc0>,
 <pickle.PickleBuffer object at 0x14699c75d040>,
 <pickle.PickleBuffer object at 0x14699c75d0c0>,
 <pickle.PickleBuffer object at 0x14699c75d140>,
 <pickle.PickleBuffer object at 0x14699c75d1c0>,
 <pickle.PickleBuffer object at 0x14699c75d240>,
 <pickle.PickleBuffer object at 0x14699c75d2c0>,
 <pickle.PickleBuffer object at 0x14699c75d340>]
dump_kwargs = {'buffer_callback': <built-in method append of list object at 0x146946423540>,
 'protocol': 5}
f          = <_io.BytesIO object at 0x146945c19080>
pickler    = <distributed.protocol.pickle._DaskPickler object at 0x146b1d82ae10>
protocol   = None
x          = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>

.../test-env/lib/python3.13.../distributed/protocol/pickle.py:65: TypeError

During handling of the above exception, another exception occurred:

x = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>
serializers = ('dask', 'pickle'), on_error = 'raise', context = None
iterate_collection = None

    def serialize(  # type: ignore[no-untyped-def]
        x: object,
        serializers=None,
        on_error: Literal["message" | "raise"] = "message",
        context=None,
        iterate_collection: bool | None = None,
    ) -> tuple[dict[str, Any], list[bytes | memoryview]]:
        r"""
        Convert object to a header and list of bytestrings
    
        This takes in an arbitrary Python object and returns a msgpack serializable
        header and a list of bytes or memoryview objects.
    
        The serialization protocols to use are configurable: a list of names
        define the set of serializers to use, in order. These names are keys in
        the ``serializer_registry`` dict (e.g., 'pickle', 'msgpack'), which maps
        to the de/serialize functions. The name 'dask' is special, and will use the
        per-class serialization methods. ``None`` gives the default list
        ``['dask', 'pickle']``.
    
        Notes on the ``iterate_collection`` argument (only relevant when
        ``x`` is a collection):
        - ``iterate_collection=True``: Serialize collection elements separately.
        - ``iterate_collection=False``: Serialize collection elements together.
        - ``iterate_collection=None`` (default): Infer the best setting.
    
        Examples
        --------
        >>> serialize(1)
        ({}, [b'\x80\x04\x95\x03\x00\x00\x00\x00\x00\x00\x00K\x01.'])
    
        >>> serialize(b'123')  # some special types get custom treatment
        ({'type': 'builtins.bytes'}, [b'123'])
    
        >>> deserialize(*serialize(1))
        1
    
        Returns
        -------
        header: dictionary containing any msgpack-serializable metadata
        frames: list of bytes or memoryviews, commonly of length one
    
        See Also
        --------
        deserialize : Convert header and frames back to object
        to_serialize : Mark that data in a message should be serialized
        register_serialization : Register custom serialization functions
        """
        if serializers is None:
            serializers = ("dask", "pickle")  # TODO: get from configuration
    
        # Handle objects that are marked as `Serialize`, or that are
        # already `Serialized` objects (don't want to serialize them twice)
        if isinstance(x, Serialized):
            return x.header, x.frames
        if isinstance(x, Serialize):
            return serialize(
                x.data,
                serializers=serializers,
                on_error=on_error,
                context=context,
                iterate_collection=True,
            )
    
        # Note: don't use isinstance(), as it would match subclasses
        # (e.g. namedtuple, defaultdict) which however would revert to the base class on a
        # round-trip through msgpack
        if iterate_collection is None and type(x) in (list, set, tuple, dict):
            if type(x) is list and "msgpack" in serializers:
                # Note: "msgpack" will always convert lists to tuples
                #       (see GitHub #3716), so we should iterate
                #       through the list if "msgpack" comes before "pickle"
                #       in the list of serializers.
                iterate_collection = ("pickle" not in serializers) or (
                    serializers.index("pickle") > serializers.index("msgpack")
                )
            if not iterate_collection:
                # Check for "dask"-serializable data in dict/list/set
                iterate_collection = check_dask_serializable(x)
    
        # Determine whether keys are safe to be serialized with msgpack
        if type(x) is dict and iterate_collection:
            try:
                msgpack.dumps(list(x.keys()))
            except Exception:
                dict_safe = False
            else:
                dict_safe = True
    
        if (
            type(x) in (list, set, tuple)
            and iterate_collection
            or type(x) is dict
            and iterate_collection
            and dict_safe
        ):
            if isinstance(x, dict):
                headers_frames = []
                for k, v in x.items():
                    _header, _frames = serialize(
                        v, serializers=serializers, on_error=on_error, context=context
                    )
                    _header["key"] = k
                    headers_frames.append((_header, _frames))
            else:
                assert isinstance(x, (list, set, tuple))
                headers_frames = [
                    serialize(
                        obj, serializers=serializers, on_error=on_error, context=context
                    )
                    for obj in x
                ]
    
            frames = []
            lengths = []
            compressions: list[str | None] = []
            for _header, _frames in headers_frames:
                frames.extend(_frames)
                length = len(_frames)
                lengths.append(length)
                compressions.extend(_header.get("compression") or [None] * len(_frames))
    
            headers = {
                "sub-headers": [obj[0] for obj in headers_frames],
                "is-collection": True,
                "frame-lengths": lengths,
                "type-serialized": type(x).__name__,
            }
            if any(compression is not None for compression in compressions):
                headers["compression"] = compressions
            return headers, frames
    
        tb = ""
        exc = None
    
        for name in serializers:
            dumps, _, wants_context = families[name]
            try:
>               header, frames = dumps(x, context=context) if wants_context else dumps(x)
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^

_          = <function pickle_loads at 0x146d9ae0c720>
context    = None
dumps      = <function pickle_dumps at 0x146d9ae0c680>
exc        = TypeError("cannot pickle '_thread._local' object")
iterate_collection = None
msg        = 'Could not serialize object of type HighLevelGraph'
name       = 'pickle'
on_error   = 'raise'
serializers = ('dask', 'pickle')
str_x      = ('<ToPickle: HighLevelGraph with 1 layers.\n'
 '<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>\n'
 ' 0. i4-ed68588c42573387b6165e7033c00d8a\n'
 '>')
tb         = ('Traceback (most recent call last):\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/pickle.py", '
 'line 60, in dumps\n'
 '    result = pickle.dumps(x, **dump_kwargs)\n'
 "TypeError: cannot pickle '_thread._local' object\n"
 '\n'
 'During handling of the above exception, another exception occurred:\n'
 '\n'
 'Traceback (most recent call last):\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/pickle.py", '
 'line 65, in dumps\n'
 '    pickler.dump(x)\n'
 '    ~~~~~~~~~~~~^^^\n'
 "TypeError: cannot pickle '_thread._local' object\n"
 '\n'
 'During handling of the above exception, another exception occurred:\n'
 '\n'
 'Traceback (most recent call last):\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/serialize.py", '
 'line 366, in serialize\n'
 '    header, frames = dumps(x, context=context) if wants_context else '
 'dumps(x)\n'
 '                     ~~~~~^^^^^^^^^^^^^^^^^^^^\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/serialize.py", '
 'line 78, in pickle_dumps\n'
 '    frames[0] = pickle.dumps(\n'
 '                ~~~~~~~~~~~~^\n'
 '        x,\n'
 '        ^^\n'
 '        buffer_callback=buffer_callback,\n'
 '        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
 '        protocol=context.get("pickle-protocol", None) if context else None,\n'
 '        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
 '    )\n'
 '    ^\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/pickle.py", '
 'line 77, in dumps\n'
 '    result = cloudpickle.dumps(x, **dump_kwargs)\n'
 '  File '
 '".../test-env/lib/python3.13................../site-packages/cloudpickle/cloudpickle.py", '
 'line 1544, in dumps\n'
 '    cp.dump(obj)\n'
 '    ~~~~~~~^^^^^\n'
 '  File '
 '".../test-env/lib/python3.13................../site-packages/cloudpickle/cloudpickle.py", '
 'line 1313, in dump\n'
 '    return super().dump(obj)\n'
 '           ~~~~~~~~~~~~^^^^^\n'
 "TypeError: cannot pickle '_thread._local' object\n")
type_x     = <class 'dask.highlevelgraph.HighLevelGraph'>
wants_context = True
x          = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>

.../test-env/lib/python3.13.../distributed/protocol/serialize.py:366: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../test-env/lib/python3.13.../distributed/protocol/serialize.py:78: in pickle_dumps
    frames[0] = pickle.dumps(
        buffer_callback = <function pickle_dumps.<locals>.buffer_callback at 0x14699c7e4fe0>
        context    = None
        frames     = [None]
        writeable  = []
        x          = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>
.../test-env/lib/python3.13.../distributed/protocol/pickle.py:77: in dumps
    result = cloudpickle.dumps(x, **dump_kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        buffer_callback = <function pickle_dumps.<locals>.buffer_callback at 0x14699c7e4fe0>
        buffers    = [<pickle.PickleBuffer object at 0x14699c749ec0>,
 <pickle.PickleBuffer object at 0x14699c749f40>,
 <pickle.PickleBuffer object at 0x14699c749fc0>,
 <pickle.PickleBuffer object at 0x14699c74a040>,
 <pickle.PickleBuffer object at 0x14699c74a0c0>,
 <pickle.PickleBuffer object at 0x14699c74a140>,
 <pickle.PickleBuffer object at 0x14699c74a1c0>,
 <pickle.PickleBuffer object at 0x14699c74a240>,
 <pickle.PickleBuffer object at 0x14699c74a2c0>,
 <pickle.PickleBuffer object at 0x14699c74a3c0>,
 <pickle.PickleBuffer object at 0x14699c74a440>,
 <pickle.PickleBuffer object at 0x14699c74a4c0>,
 <pickle.PickleBuffer object at 0x14699c74a540>,
 <pickle.PickleBuffer object at 0x14699c74a5c0>,
 <pickle.PickleBuffer object at 0x14699c74a640>,
 <pickle.PickleBuffer object at 0x14699c74a6c0>,
 <pickle.PickleBuffer object at 0x14699c74a740>,
 <pickle.PickleBuffer object at 0x14699c74a340>,
 <pickle.PickleBuffer object at 0x14699c74a7c0>,
 <pickle.PickleBuffer object at 0x14699c74a840>,
 <pickle.PickleBuffer object at 0x14699c74a8c0>,
 <pickle.PickleBuffer object at 0x14699c74a940>,
 <pickle.PickleBuffer object at 0x14699c74a9c0>,
 <pickle.PickleBuffer object at 0x14699c74aa40>,
 <pickle.PickleBuffer object at 0x14699c74aac0>,
 <pickle.PickleBuffer object at 0x14699c74ab40>,
 <pickle.PickleBuffer object at 0x14699c74abc0>,
 <pickle.PickleBuffer object at 0x14699c74ac40>,
 <pickle.PickleBuffer object at 0x14699c74acc0>,
 <pickle.PickleBuffer object at 0x14699c74ad40>,
 <pickle.PickleBuffer object at 0x14699c74adc0>,
 <pickle.PickleBuffer object at 0x14699c74ae40>,
 <pickle.PickleBuffer object at 0x14699c74aec0>,
 <pickle.PickleBuffer object at 0x14699c74af40>,
 <pickle.PickleBuffer object at 0x14699c74afc0>,
 <pickle.PickleBuffer object at 0x14699c74b040>,
 <pickle.PickleBuffer object at 0x14699c74b0c0>,
 <pickle.PickleBuffer object at 0x14699c74b140>,
 <pickle.PickleBuffer object at 0x14699c74b1c0>,
 <pickle.PickleBuffer object at 0x14699c74b240>,
 <pickle.PickleBuffer object at 0x14699c74b2c0>,
 <pickle.PickleBuffer object at 0x14699c74b340>,
 <pickle.PickleBuffer object at 0x14699c74b3c0>,
 <pickle.PickleBuffer object at 0x14699c74b440>,
 <pickle.PickleBuffer object at 0x14699c74b4c0>,
 <pickle.PickleBuffer object at 0x14699c74b540>,
 <pickle.PickleBuffer object at 0x14699c74b5c0>,
 <pickle.PickleBuffer object at 0x14699c74b640>,
 <pickle.PickleBuffer object at 0x14699c74b6c0>,
 <pickle.PickleBuffer object at 0x14699c74b740>,
 <pickle.PickleBuffer object at 0x14699c74b7c0>,
 <pickle.PickleBuffer object at 0x14699c74b840>,
 <pickle.PickleBuffer object at 0x14699c74b8c0>,
 <pickle.PickleBuffer object at 0x14699c74b940>,
 <pickle.PickleBuffer object at 0x14699c74b9c0>,
 <pickle.PickleBuffer object at 0x14699c74ba40>,
 <pickle.PickleBuffer object at 0x14699c74bac0>,
 <pickle.PickleBuffer object at 0x14699c74bb40>,
 <pickle.PickleBuffer object at 0x14699c74bbc0>,
 <pickle.PickleBuffer object at 0x14699c74bc40>,
 <pickle.PickleBuffer object at 0x14699c74bcc0>,
 <pickle.PickleBuffer object at 0x14699c74bd40>,
 <pickle.PickleBuffer object at 0x14699c74bdc0>,
 <pickle.PickleBuffer object at 0x14699c74be40>,
 <pickle.PickleBuffer object at 0x14699c74bec0>,
 <pickle.PickleBuffer object at 0x14699c74bf40>,
 <pickle.PickleBuffer object at 0x14699c75c040>,
 <pickle.PickleBuffer object at 0x14699c75c0c0>,
 <pickle.PickleBuffer object at 0x14699c75c140>,
 <pickle.PickleBuffer object at 0x14699c75c1c0>,
 <pickle.PickleBuffer object at 0x14699c75c240>,
 <pickle.PickleBuffer object at 0x14699c75c2c0>,
 <pickle.PickleBuffer object at 0x14699c75c340>,
 <pickle.PickleBuffer object at 0x14699c75c3c0>,
 <pickle.PickleBuffer object at 0x14699c75c440>,
 <pickle.PickleBuffer object at 0x14699c75c4c0>,
 <pickle.PickleBuffer object at 0x14699c75c540>,
 <pickle.PickleBuffer object at 0x14699c75c5c0>,
 <pickle.PickleBuffer object at 0x14699c75c640>,
 <pickle.PickleBuffer object at 0x14699c75c6c0>,
 <pickle.PickleBuffer object at 0x14699c75c740>,
 <pickle.PickleBuffer object at 0x14699c75c7c0>,
 <pickle.PickleBuffer object at 0x14699c75c840>,
 <pickle.PickleBuffer object at 0x14699c75c8c0>,
 <pickle.PickleBuffer object at 0x14699c75c940>,
 <pickle.PickleBuffer object at 0x14699c75c9c0>,
 <pickle.PickleBuffer object at 0x14699c75ca40>,
 <pickle.PickleBuffer object at 0x14699c75cac0>,
 <pickle.PickleBuffer object at 0x14699c75cb40>,
 <pickle.PickleBuffer object at 0x14699c75cbc0>,
 <pickle.PickleBuffer object at 0x14699c75cc40>,
 <pickle.PickleBuffer object at 0x14699c75ccc0>,
 <pickle.PickleBuffer object at 0x14699c75cd40>,
 <pickle.PickleBuffer object at 0x14699c75cdc0>,
 <pickle.PickleBuffer object at 0x14699c75ce40>,
 <pickle.PickleBuffer object at 0x14699c75cec0>,
 <pickle.PickleBuffer object at 0x14699c75cf40>,
 <pickle.PickleBuffer object at 0x14699c75cfc0>,
 <pickle.PickleBuffer object at 0x14699c75d040>,
 <pickle.PickleBuffer object at 0x14699c75d0c0>,
 <pickle.PickleBuffer object at 0x14699c75d140>,
 <pickle.PickleBuffer object at 0x14699c75d1c0>,
 <pickle.PickleBuffer object at 0x14699c75d240>,
 <pickle.PickleBuffer object at 0x14699c75d2c0>,
 <pickle.PickleBuffer object at 0x14699c75d340>]
        dump_kwargs = {'buffer_callback': <built-in method append of list object at 0x146946423540>,
 'protocol': 5}
        f          = <_io.BytesIO object at 0x146945c19080>
        pickler    = <distributed.protocol.pickle._DaskPickler object at 0x146b1d82ae10>
        protocol   = None
        x          = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>
.../test-env/lib/python3.13................../site-packages/cloudpickle/cloudpickle.py:1544: in dumps
    cp.dump(obj)
        buffer_callback = <built-in method append of list object at 0x146946423540>
        cp         = <cloudpickle.cloudpickle.Pickler object at 0x146b1d82b410>
        file       = <_io.BytesIO object at 0x146945c1b740>
        obj        = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>
        protocol   = 5
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <cloudpickle.cloudpickle.Pickler object at 0x146b1d82b410>
obj = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>

    def dump(self, obj):
        try:
>           return super().dump(obj)
                   ^^^^^^^^^^^^^^^^^
E           TypeError: cannot pickle '_thread._local' object

__class__  = <class 'cloudpickle.cloudpickle.Pickler'>
obj        = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>
self       = <cloudpickle.cloudpickle.Pickler object at 0x146b1d82b410>

.../test-env/lib/python3.13................../site-packages/cloudpickle/cloudpickle.py:1313: TypeError

The above exception was the direct cause of the following exception:

    def test_decompression_executor_for_dask():
    
        class TestExecutor(uproot.source.futures.TrivialExecutor):
            def __init__(self):
                self.submit_count = 0
    
            def submit(self, task, /, *args, **kwargs):
                self.submit_count += 1
                super().submit(task, *args, **kwargs)
    
        testexecutor = TestExecutor()
    
        a = uproot.dask(
            {skhep_testdata.data_path("uproot-sample-6.20.04-uncompressed.root"): "sample"},
            decompression_executor=testexecutor,
        )
    
>       a["i4"].compute()

TestExecutor = <class 'tests.test_1120_check_decompression_executor_pass_for_dask.test_decompression_executor_for_dask.<locals>.TestExecutor'>
a          = dask.awkward<from-uproot, type='30 * {n: int32, b: bool, ab: 3 * bool, Ab: var * bool, ...', npartitions=1>
testexecutor = <TestExecutor at 0x146b1cc43230>

tests/test_1120_check_decompression_executor_pass_for_dask.py:29: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../test-env/lib/python3.13....../site-packages/dask/base.py:370: in compute
    (result,) = compute(self, traverse=False, **kwargs)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        kwargs     = {}
        self       = dask.awkward<i4, type='30 * int32', npartitions=1>
.../test-env/lib/python3.13....../site-packages/dask/base.py:656: in compute
    results = schedule(dsk, keys, **kwargs)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        args       = (dask.awkward<i4, type='30 * int32', npartitions=1>,)
        collections = [dask.awkward<i4, type='30 * int32', npartitions=1>]
        dsk        = HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a

        get        = None
        keys       = [[('i4-ed68588c42573387b6165e7033c00d8a', 0)]]
        kwargs     = {}
        optimize_graph = True
        postcomputes = [(<function _finalize_array at 0x146d9bc98a40>, ())]
        repack     = <function unpack_collections.<locals>.repack at 0x14699c7e4220>
        schedule   = <bound method Client.get of <Client: No scheduler connected>>
        scheduler  = None
        traverse   = False
        x          = dask.awkward<i4, type='30 * int32', npartitions=1>
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

x = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>
serializers = ('dask', 'pickle'), on_error = 'raise', context = None
iterate_collection = None

    def serialize(  # type: ignore[no-untyped-def]
        x: object,
        serializers=None,
        on_error: Literal["message" | "raise"] = "message",
        context=None,
        iterate_collection: bool | None = None,
    ) -> tuple[dict[str, Any], list[bytes | memoryview]]:
        r"""
        Convert object to a header and list of bytestrings
    
        This takes in an arbitrary Python object and returns a msgpack serializable
        header and a list of bytes or memoryview objects.
    
        The serialization protocols to use are configurable: a list of names
        define the set of serializers to use, in order. These names are keys in
        the ``serializer_registry`` dict (e.g., 'pickle', 'msgpack'), which maps
        to the de/serialize functions. The name 'dask' is special, and will use the
        per-class serialization methods. ``None`` gives the default list
        ``['dask', 'pickle']``.
    
        Notes on the ``iterate_collection`` argument (only relevant when
        ``x`` is a collection):
        - ``iterate_collection=True``: Serialize collection elements separately.
        - ``iterate_collection=False``: Serialize collection elements together.
        - ``iterate_collection=None`` (default): Infer the best setting.
    
        Examples
        --------
        >>> serialize(1)
        ({}, [b'\x80\x04\x95\x03\x00\x00\x00\x00\x00\x00\x00K\x01.'])
    
        >>> serialize(b'123')  # some special types get custom treatment
        ({'type': 'builtins.bytes'}, [b'123'])
    
        >>> deserialize(*serialize(1))
        1
    
        Returns
        -------
        header: dictionary containing any msgpack-serializable metadata
        frames: list of bytes or memoryviews, commonly of length one
    
        See Also
        --------
        deserialize : Convert header and frames back to object
        to_serialize : Mark that data in a message should be serialized
        register_serialization : Register custom serialization functions
        """
        if serializers is None:
            serializers = ("dask", "pickle")  # TODO: get from configuration
    
        # Handle objects that are marked as `Serialize`, or that are
        # already `Serialized` objects (don't want to serialize them twice)
        if isinstance(x, Serialized):
            return x.header, x.frames
        if isinstance(x, Serialize):
            return serialize(
                x.data,
                serializers=serializers,
                on_error=on_error,
                context=context,
                iterate_collection=True,
            )
    
        # Note: don't use isinstance(), as it would match subclasses
        # (e.g. namedtuple, defaultdict) which however would revert to the base class on a
        # round-trip through msgpack
        if iterate_collection is None and type(x) in (list, set, tuple, dict):
            if type(x) is list and "msgpack" in serializers:
                # Note: "msgpack" will always convert lists to tuples
                #       (see GitHub #3716), so we should iterate
                #       through the list if "msgpack" comes before "pickle"
                #       in the list of serializers.
                iterate_collection = ("pickle" not in serializers) or (
                    serializers.index("pickle") > serializers.index("msgpack")
                )
            if not iterate_collection:
                # Check for "dask"-serializable data in dict/list/set
                iterate_collection = check_dask_serializable(x)
    
        # Determine whether keys are safe to be serialized with msgpack
        if type(x) is dict and iterate_collection:
            try:
                msgpack.dumps(list(x.keys()))
            except Exception:
                dict_safe = False
            else:
                dict_safe = True
    
        if (
            type(x) in (list, set, tuple)
            and iterate_collection
            or type(x) is dict
            and iterate_collection
            and dict_safe
        ):
            if isinstance(x, dict):
                headers_frames = []
                for k, v in x.items():
                    _header, _frames = serialize(
                        v, serializers=serializers, on_error=on_error, context=context
                    )
                    _header["key"] = k
                    headers_frames.append((_header, _frames))
            else:
                assert isinstance(x, (list, set, tuple))
                headers_frames = [
                    serialize(
                        obj, serializers=serializers, on_error=on_error, context=context
                    )
                    for obj in x
                ]
    
            frames = []
            lengths = []
            compressions: list[str | None] = []
            for _header, _frames in headers_frames:
                frames.extend(_frames)
                length = len(_frames)
                lengths.append(length)
                compressions.extend(_header.get("compression") or [None] * len(_frames))
    
            headers = {
                "sub-headers": [obj[0] for obj in headers_frames],
                "is-collection": True,
                "frame-lengths": lengths,
                "type-serialized": type(x).__name__,
            }
            if any(compression is not None for compression in compressions):
                headers["compression"] = compressions
            return headers, frames
    
        tb = ""
        exc = None
    
        for name in serializers:
            dumps, _, wants_context = families[name]
            try:
                header, frames = dumps(x, context=context) if wants_context else dumps(x)
                header["serializer"] = name
                return header, frames
            except NotImplementedError:
                continue
            except Exception as e:
                exc = e
                tb = traceback.format_exc()
                break
        type_x = type(x)
        if isinstance(x, (ToPickle, Serialize)):
            type_x = type(x.data)
        msg = f"Could not serialize object of type {type_x.__name__}"
        if on_error == "message":
            txt_frames = [msg]
            if tb:
                txt_frames.append(tb[:100000])
    
            frames = [frame.encode() for frame in txt_frames]
    
            return {"serializer": "error"}, frames
        elif on_error == "raise":
            try:
                str_x = str(x)[:10000]
            except Exception:
                raise TypeError(msg) from exc
>           raise TypeError(msg, str_x) from exc
E           TypeError: ('Could not serialize object of type HighLevelGraph', '<ToPickle: HighLevelGraph with 1 layers.\n<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>\n 0. i4-ed68588c42573387b6165e7033c00d8a\n>')

_          = <function pickle_loads at 0x146d9ae0c720>
context    = None
dumps      = <function pickle_dumps at 0x146d9ae0c680>
exc        = TypeError("cannot pickle '_thread._local' object")
iterate_collection = None
msg        = 'Could not serialize object of type HighLevelGraph'
name       = 'pickle'
on_error   = 'raise'
serializers = ('dask', 'pickle')
str_x      = ('<ToPickle: HighLevelGraph with 1 layers.\n'
 '<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>\n'
 ' 0. i4-ed68588c42573387b6165e7033c00d8a\n'
 '>')
tb         = ('Traceback (most recent call last):\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/pickle.py", '
 'line 60, in dumps\n'
 '    result = pickle.dumps(x, **dump_kwargs)\n'
 "TypeError: cannot pickle '_thread._local' object\n"
 '\n'
 'During handling of the above exception, another exception occurred:\n'
 '\n'
 'Traceback (most recent call last):\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/pickle.py", '
 'line 65, in dumps\n'
 '    pickler.dump(x)\n'
 '    ~~~~~~~~~~~~^^^\n'
 "TypeError: cannot pickle '_thread._local' object\n"
 '\n'
 'During handling of the above exception, another exception occurred:\n'
 '\n'
 'Traceback (most recent call last):\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/serialize.py", '
 'line 366, in serialize\n'
 '    header, frames = dumps(x, context=context) if wants_context else '
 'dumps(x)\n'
 '                     ~~~~~^^^^^^^^^^^^^^^^^^^^\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/serialize.py", '
 'line 78, in pickle_dumps\n'
 '    frames[0] = pickle.dumps(\n'
 '                ~~~~~~~~~~~~^\n'
 '        x,\n'
 '        ^^\n'
 '        buffer_callback=buffer_callback,\n'
 '        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
 '        protocol=context.get("pickle-protocol", None) if context else None,\n'
 '        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
 '    )\n'
 '    ^\n'
 '  File '
 '".../test-env/lib/python3.13.../distributed/protocol/pickle.py", '
 'line 77, in dumps\n'
 '    result = cloudpickle.dumps(x, **dump_kwargs)\n'
 '  File '
 '".../test-env/lib/python3.13................../site-packages/cloudpickle/cloudpickle.py", '
 'line 1544, in dumps\n'
 '    cp.dump(obj)\n'
 '    ~~~~~~~^^^^^\n'
 '  File '
 '".../test-env/lib/python3.13................../site-packages/cloudpickle/cloudpickle.py", '
 'line 1313, in dump\n'
 '    return super().dump(obj)\n'
 '           ~~~~~~~~~~~~^^^^^\n'
 "TypeError: cannot pickle '_thread._local' object\n")
type_x     = <class 'dask.highlevelgraph.HighLevelGraph'>
wants_context = True
x          = <ToPickle: HighLevelGraph with 1 layers.
<dask.highlevelgraph.HighLevelGraph object at 0x14699c79f930>
 0. i4-ed68588c42573387b6165e7033c00d8a
>

.../test-env/lib/python3.13.../distributed/protocol/serialize.py:392: TypeError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@TaiSakuma TaiSakuma added the type/fix PR title type: fix (set automatically) label Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/fix PR title type: fix (set automatically)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants