Skip to content

Fix IndexOutOfRangeException on empty **kwargs call to overloaded method#133

Merged
jhonabreul merged 2 commits into
QuantConnect:masterfrom
jhonabreul:bug-132-empty-kwargs-overload-binding
Jul 9, 2026
Merged

Fix IndexOutOfRangeException on empty **kwargs call to overloaded method#133
jhonabreul merged 2 commits into
QuantConnect:masterfrom
jhonabreul:bug-132-empty-kwargs-overload-binding

Conversation

@jhonabreul

@jhonabreul jhonabreul commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Description

Calling an overloaded .NET method from Python with an empty **kwargs mapping (e.g. obj.Method(arg, **{}), common when forwarding *args/**kwargs from a wrapper or decorator) crashed with an unhandled System.IndexOutOfRangeException in MethodBinder.CheckMethodArgumentsMatch. The exception escapes through tp_call as a CLR exception, so it cannot be caught from Python and tears down the host process (crashes LEAN during Initialize()).

Closes #132

Also bumps the package version to 2.0.60 (package <Version>, AssemblyVersion/AssemblyFileVersion and the perf-test baseline reference, following the same pattern as #131).

Root cause

Since 10e721b (#83), the parameter names array is only populated when there are named arguments (hasNamedArgs ? methodInformation.ParameterNames : Array.Empty<string>()), but the kwargs code paths in CheckMethodArgumentsMatch and Bind only checked the kwargs dictionary for null. A non-null but empty kwargs dict therefore routed binding through the kwargs path while paramNames was empty, indexing out of range for any overload with more CLR parameters than positional Python arguments. Bisect-confirmed: 10e721b~1 binds fine, 10e721b crashes.

Fix

Treat an empty kwargs dict as no keyword arguments: MethodBinder.Bind only builds kwArgDict when PyDict_Size(kw) > 0, so **{} follows the exact same code path as a plain positional call. This matches pure Python semantics, where f(x, **{}) is equivalent to f(x), and restores the invariant that a non-null kwArgDict implies populated parameter names.

Testing

  • New TestMethodBinder.BindsOverloadedMethodCalledWithEmptyOrUnpackedKwargs covering empty **{} against overloads of different arity, empty **{} mixed with a named argument, non-empty dict unpacking, overloads with default parameter values, and the *args/**kwargs forwarding idiom from the issue. Without the fix, these crash the test host.
  • Full embedding test suite passes (927 passed, 0 failed).
  • Full CI suite replicated locally in the quantconnect/lean:foundation container (Python 3.11.14): embedding tests 928/928, pytest suite 454 passed, python_tests_runner 2/2.
  • Verified in LEAN: the issue's get_parameter wrapper algorithm crashes on the current binaries and completes successfully with the fixed Python.Runtime.dll.

…hod (QuantConnect#132)

Calling an overloaded method with an empty kwargs mapping (e.g.
obj.Method(arg, **{}), common when forwarding *args/**kwargs from a
wrapper) crashed with an unhandled IndexOutOfRangeException in
MethodBinder.CheckMethodArgumentsMatch. Since 10e721b (PR QuantConnect#83), the
parameter names array is only populated when there are named arguments,
but the kwargs code paths only checked the kwargs dictionary for null,
so a non-null empty dict indexed into an empty names array.

Treat an empty kwargs dict as no keyword arguments, matching Python
semantics where f(x, **{}) is equivalent to f(x).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jhonabreul jhonabreul marked this pull request as ready for review July 9, 2026 18:16
Bump package <Version>, AssemblyVersion/AssemblyFileVersion and the
perf-test baseline reference to 2.0.60.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jhonabreul jhonabreul merged commit 1c136b6 into QuantConnect:master Jul 9, 2026
7 checks passed
@jhonabreul jhonabreul deleted the bug-132-empty-kwargs-overload-binding branch July 9, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MethodBinder.CheckMethodArgumentsMatch throws unhandled IndexOutOfRangeException on empty **kwargs call to an overloaded method

2 participants