Things to check first
Typeguard version
4.5.1
Python version
3.14.4
What happened?
typeguard.check_type(value, SomeProtocol) crashed with IndexError: pop from empty list instead of returning or raising TypeCheckError.
File ".../typeguard/_checkers.py", line 769, in check_signature_compatible
subject_args.pop(0)
IndexError: pop from empty list
The two pop(0) calls in check_signature_compatible :
|
if protocol_type == "instance": |
|
protocol_args.pop(0) |
|
|
|
# Remove the "self" parameter from the subject arguments to match |
|
if subject_type == "instance": |
|
subject_args.pop(0) |
If inspect.signature(subject_attr) reports zero positional-or-keyword params and no *args, subject_args is empty and the pop blows up. Callable instances, partials, and other non-staticmethod/non-classmethod descriptors all hit this path.
What I expected was a TypeCheckError. The same arity mismatch with one more positional arg on the subject raises a clean TypeCheckError ("too few positional arguments"). Drop the count by one and it becomes IndexError. Equivalent mismatch, two different exception types, only one of which check_type is documented to raise, so callers catching TypeCheckError leak the IndexError through.
The fix I am running locally is to guard each pop:
if protocol_type == "instance" and protocol_args:
protocol_args.pop(0)
if subject_type == "instance" and subject_args:
subject_args.pop(0)
With that, the repro raises TypeCheckError and the rest of the test suite still passes for me.
Happy to PR with a regression test under tests/test_checkers.py::TestProtocol. If you would rather the empty case raise an explicit TypeCheckError earlier with a more specific message, let me know and I will rework.
How can we reproduce the bug?
Stdlib only, no third-party deps:
from typing import Protocol
from typeguard import check_type
class _ZeroArg:
def __call__(self):
return None
class Subject:
method = _ZeroArg()
class P(Protocol):
def method(self, x: int) -> None: ...
check_type(Subject(), P)
# IndexError: pop from empty list
Run on Python 3.14, typeguard 4.5.1.
Things to check first
I have searched the existing issues and didn't find my bug already reported there
I have checked that my bug is still present in the latest release
Typeguard version
4.5.1
Python version
3.14.4
What happened?
typeguard.check_type(value, SomeProtocol)crashed withIndexError: pop from empty listinstead of returning or raisingTypeCheckError.The two
pop(0)calls incheck_signature_compatible:typeguard/src/typeguard/_checkers.py
Lines 764 to 769 in ff2b88b
If
inspect.signature(subject_attr)reports zero positional-or-keyword params and no*args,subject_argsis empty and the pop blows up. Callable instances, partials, and other non-staticmethod/non-classmethod descriptors all hit this path.What I expected was a
TypeCheckError. The same arity mismatch with one more positional arg on the subject raises a cleanTypeCheckError("too few positional arguments"). Drop the count by one and it becomesIndexError. Equivalent mismatch, two different exception types, only one of whichcheck_typeis documented to raise, so callers catchingTypeCheckErrorleak theIndexErrorthrough.The fix I am running locally is to guard each pop:
With that, the repro raises
TypeCheckErrorand the rest of the test suite still passes for me.Happy to PR with a regression test under
tests/test_checkers.py::TestProtocol. If you would rather the empty case raise an explicitTypeCheckErrorearlier with a more specific message, let me know and I will rework.How can we reproduce the bug?
Stdlib only, no third-party deps:
Run on Python 3.14, typeguard 4.5.1.