Subclassing `ObjectDoesNotExist` and forwarding `**kwargs` fails mypy
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 45/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Quiet
- Tech stack
- python
Research direction
Start with src/libtmux/exc.py and inspect the typed init signatures for ObjectDoesNotExist and MultipleObjectsReturned. Reproduce the failure with the provided subclass and mypy, then evaluate the documented catch-all and migration-note options. Done means the chosen behavior is documented or implemented without losing direct checking of query and count.
Written by the indexing model from the issue text.
Description
Summary
ObjectDoesNotExist.__init__ and MultipleObjectsReturned.__init__ gained typed keyword-only parameters in v0.62.0. A subclass that forwards **kwargs to super().__init__ — the ordinary way to extend an exception — no longer type-checks, because mypy validates the unpacked mapping against every declared keyword parameter. Runtime behavior is unaffected; only type-checking fails.
tmuxp hits this in tmuxp/exc.py. It is currently pinned to libtmux 0.61.0, so the failure appears the moment that pin moves.
Reproduction
from libtmux.exc import ObjectDoesNotExist
class SessionMissing(ObjectDoesNotExist):
def __init__(self, *args: object, **kwargs: object) -> None:
super().__init__("no session", *args, **kwargs)
$ mypy repro.py
Expected
Type-checks. The call is correct at runtime, and forwarding **kwargs is the conventional way to subclass an exception.
Actual
error: Argument 3 to "__init__" of "ObjectDoesNotExist" has incompatible type "**dict[str, object]"; expected "Mapping[str, Any] | None" [arg-type]
Widening the subclass to **kwargs: t.Any silences it, but that is a downstream workaround for an upstream signature change, and it gives up the subclass's own annotation.
Environment
libtmux 0.62.0
mypy 2.3.0
Python 3.14.6
Evidence
Against tmuxp's checkout, changing only the installed libtmux:
$ uv pip install 'libtmux==0.61.0' && uv run mypy src
Success: no issues found in 41 source files
$ uv pip install 'libtmux==0.62.0' && uv run mypy src
src/tmuxp/exc.py:86: error: Argument 3 to "__init__" of "ObjectDoesNotExist" has incompatible type "**dict[str, object]"; expected "Mapping[str, Any] | None" [arg-type]
Found 1 error in 1 file (checked 41 source files)
Proposal
Two options, neither obviously right.
Accept a **kwargs catch-all upstream
Add **kwargs: t.Any to both __init__ signatures and raise TypeError for anything unrecognized, so a typo is still caught.
This was measured and does not fix the reported error: mypy still binds the unpacked mapping against query, so the catch-all changes nothing for the subclass. It also replaces CPython's own message — which suggests the intended keyword — with a hand-written one:
# CPython
TypeError: __init__() got an unexpected keyword argument 'qeury'. Did you mean 'query'?
# hand-written
TypeError: unexpected keyword argument: qeury
Recorded here so the next person does not re-derive it.
Document it as a deliberate tightening
Leave the signatures alone and add a MIGRATION note telling downstream subclasses to annotate **kwargs: t.Any. This keeps query and count statically checked for direct callers, which is what made them worth adding.
References
ObjectDoesNotExistandMultipleObjectsReturnedinsrc/libtmux/exc.py- v0.62.0 release, which notes the exception-hierarchy change but not the subclassing effect
- Dominant language
- Python
- Stars
- 1.2k
- Forks
- 127
- Avg merge
- 2h 13m
- Merged PRs (30d)
- 1
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from tmux-python/libtmux
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
tmux-python/libtmux#759 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
tmux-python/libtmux#745 · 2 comments ·
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
tmux-python/libtmux#744 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
tmux-python/libtmux#731 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
tmux-python/libtmux#654 ·
All issues in tmux-python/libtmux
Similar issues
-
area: harness bug status: needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Human-Agent-Society/reef#625 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
Difficulty 1/5 Under an hour Newbie friendliness 80/100
learningequality/kolibri#15351 · 2 comments ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
Name consistency Open
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
eellak/triplestore#65 · 1 comment ·