Skip to content

fix: rebuild namedtuples in _deepcopy_with_exceptions#11981

Open
chuenchen309 wants to merge 1 commit into
deepset-ai:mainfrom
chuenchen309:fix/deepcopy-namedtuple-reconstruction
Open

fix: rebuild namedtuples in _deepcopy_with_exceptions#11981
chuenchen309 wants to merge 1 commit into
deepset-ai:mainfrom
chuenchen309:fix/deepcopy-namedtuple-reconstruction

Conversation

@chuenchen309

Copy link
Copy Markdown
Contributor

What

_deepcopy_with_exceptions (used when Haystack copies component inputs/params) is designed to degrade gracefully: if an object cannot be deep-copied it returns the original and logs. But its container branch crashes on a namedtuple:

if isinstance(obj, (list, tuple, set)):
    return type(obj)(_deepcopy_with_exceptions(v) for v in obj)

A namedtuple is a tuple subclass, so it takes this branch — but type(obj)(<generator>) calls the namedtuple's __new__ with a single iterable, whereas its __new__ expects the fields as positional arguments. The result is an uncaught TypeError, which propagates out of the copy (also through any dict/list that contains the namedtuple), defeating the function's own graceful-fallback contract.

Reproduction:

from collections import namedtuple
from haystack.core.pipeline.utils import _deepcopy_with_exceptions

Point = namedtuple("Point", ["x", "y"])
_deepcopy_with_exceptions({"pt": Point(1, 2)})
# TypeError: Point.__new__() missing 1 required positional argument: 'y'

Fix

Handle namedtuples explicitly (detected via the _fields attribute) before the generic list/tuple/set branch, rebuilding them by unpacking their deep-copied fields. Plain tuples/lists/sets are unaffected.

Test

Added TestDeepcopyWithFallback::test_deepcopy_with_fallback_namedtuple, which fails before the change (the TypeError above) and passes after, verifying the namedtuple is reconstructed as its own type with deep-copied contents.

Verified locally: the full test/core/pipeline/test_utils.py suite passes (27 passed). ruff check and ruff format --check are clean. Added a release note.


Authored with AI assistance (Claude Code); the change and tests were reviewed and verified locally by me.

_deepcopy_with_exceptions rebuilt list/tuple/set values with
type(obj)(<generator>), but a namedtuple's __new__ takes its fields
positionally, not as a single iterable. Copying a component input or
parameter that held a namedtuple therefore raised TypeError, defeating
the function's graceful-fallback contract. Rebuild namedtuples by
unpacking their deep-copied fields.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chuenchen309 chuenchen309 requested a review from a team as a code owner July 13, 2026 09:52
@chuenchen309 chuenchen309 requested review from bogdankostic and removed request for a team July 13, 2026 09:52
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

@chuenchen309 is attempting to deploy a commit to the deepset Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  haystack/core/pipeline
  utils.py
Project Total  

This report was generated by python-coverage-comment-action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant