Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Sockets.__getattribute__ references _sockets but the actual attribute is _sockets_dict — the optimization at lines 127-132 is dead code due to a typo

Open Beginner friendly
#12,939 1 comment 0 reactions 1 assignee View on GitHub

Maintainers usually reply within 1 day

@julian-risch is already working on this.

Since Sep 25, 2026.

Assessment

Difficulty
1/5
Estimated time
Under an hour
Newbie friendliness
91/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
backend

Research direction

Open haystack/core/component/sockets.py and inspect init alongside getattribute. Change the attribute name used by the lookup to match _sockets_dict, then run hatch -e default run pytest test/core -q. Done means _sockets is no longer referenced and the existing socket accessors continue producing their current results.

Written by the indexing model from the issue text.

Description

P2

Sockets.__getattribute__ references _sockets but the attribute is actually _sockets_dict — the optimization is dead code

Problem

haystack/core/component/sockets.py:126-134 defines a custom __getattribute__ that looks up the name in self._sockets — but the actual instance attribute is named self._sockets_dict (set in __init__ at line 77). The try block at lines 127-132 always raises AttributeError and falls through to object.__getattribute__(self, name) at line 134.

The class still works because __init__ does self.__dict__.update(sockets_dict) at line 78, which exposes each socket as a regular instance attribute. The custom __getattribute__ looks like an intended optimization (skip default attribute machinery and look up directly in the dict) but it never fires.

Evidence (against current main 43547276ad)

# haystack/core/component/sockets.py, lines 53-78
    def __init__(
        self,
        component: "Component",  # type: ignore[name-defined] # noqa: F821
        sockets_dict: SocketsDict,
        sockets_io_type: SocketsIOType,
    ) -> None:
        ...
        self._sockets_io_type = sockets_io_type                              # line 75
        self._component = component                                           # line 76
        self._sockets_dict = sockets_dict                                     # line 77
        self.__dict__.update(sockets_dict)                                   # line 78

# haystack/core/component/sockets.py, lines 126-134
    def __getattribute__(self, name: Any) -> Any:
        try:
            sockets = object.__getattribute__(self, "_sockets")              # line 128
            if name in sockets:
                return sockets[name]
        except AttributeError:
            pass

        return object.__getattribute__(self, name)

_sockets is never set anywhere in the file. _sockets_dict is set at line 77 and used at lines 87, 97, 101, 114, 143.

Verified locally against current main (43547276ad) via hatch -e default run python:

from typing import Any
from haystack.core.component.sockets import Sockets
from haystack.core.component.types import InputSocket

class FakeComponent:
    pass

sockets_dict = {
    "question": InputSocket("question", Any),
    "documents": InputSocket("documents", Any),
}
s = Sockets(component=FakeComponent(), sockets_dict=sockets_dict, sockets_io_type=InputSocket)

>>> hasattr(s, "_sockets")
False
>>> hasattr(s, "_sockets_dict")
True
>>> s.question
InputSocket(name='question', type=typing.Any, default_value=<class '_empty'>, is_lazy_variadic=False, is_greedy=False, senders=[], wrap_input_in_list=True)
>>> s.documents
InputSocket(...)
>>> object.__getattribute__(s, '_sockets')
AttributeError: 'Sockets' object has no attribute '_sockets'

So every call to __getattribute__ raises AttributeError on line 128 and falls through to object.__getattribute__ on line 134. The optimization looks like the intended hot-path (skip default attribute machinery and look up directly in the dict) but it never runs.

Why it matters

The bug is two-fold:

  1. Latent correctness issue. Any future change that removes self.__dict__.update(sockets_dict) at line 78 (e.g., to fix a different issue) would break the class immediately, because the __getattribute__ doesn't actually fall back to the dict. The current __dict__.update is the only reason s.question works. There is no test or comment explaining why __getattribute__ exists.

  2. Performance issue (minor). Every socket attribute access incurs the failed try/except + the default attribute lookup. For pipelines that introspect sockets (e.g., for type checking in Pipeline.run_async), this is a small overhead per call.

  3. Documentation hygiene. The custom __getattribute__ is a misleading piece of code. Future maintainers reading this will assume it works and may add more logic on top of it without realizing the try block is dead.

Proposed fix

One-character fix in __getattribute__ on line 128:

# Before
sockets = object.__getattribute__(self, "_sockets")

# After
sockets = object.__getattribute__(self, "_sockets_dict")

That's the entire fix. Two alternatives considered below.

Alternatives considered

  • Remove __getattribute__ entirely, rely on self.__dict__.update(sockets_dict) at line 78. The class already supports attribute access via __dict__.update; the custom method is redundant once we acknowledge the actual behavior. Cleaner long-term, but a slightly larger diff (delete 9 lines). Rejected as out of scope for a minimal cycle-36 fix; can be a follow-up.
  • Make __getattribute__ symmetric with the rest of the API by also reading _sockets_dict in __setitem__ (line 97), __contains__ (line 101), get (line 114), and __repr__ (line 143). The other accessors already use _sockets_dict correctly — only __getattribute__ is broken. Rejected; the other accessors are already correct.

Scope

  • One file: haystack/core/component/sockets.py
  • One line of code changed (line 128)
  • One line of the docstring at line 126 unchanged (the function-level docstring isn't there for this method)
  • No public API change, no behavior change, no test change

Backward compatibility

None. The fix makes __getattribute__ actually run the optimization it appears to be doing. External callers see no difference; sockets["foo"], sockets.get("foo"), sockets.foo, "foo" in sockets, sockets == sockets2 all continue to work.

Acceptance criteria

  • self._sockets is no longer referenced in sockets.py
  • hasattr(s, "_sockets") becomes True after construction (because __getattribute__ now reads _sockets_dict)
  • s.question, s.documents, sockets.__contains__("question"), sockets.get("question"), sockets.__repr__() all continue to produce the same results as before
  • hatch -e default run pytest test/core -q (or equivalent) passes without modification

Risks

None. The fix is one-character; the function's behavior with the fix matches what the surrounding __dict__.update already provides.

Dominant language
Python
Stars
26.6k
Forks
3.2k
Avg merge
1d 13h
Merged PRs (30d)
263

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from deepset-ai/haystack

All issues in deepset-ai/haystack

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.