GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — [Bug]: `itertools.groupby` group iterator re-entered from the key's `__eq__` returns a Java `null`, which crashes with `NullPointerException` · Issue #1276 · oracle/graalpython

[Bug]: itertools.groupby group iterator re-entered from the key's __eq__ returns a Java null, which crashes with NullPointerException #1276

New issue
Copy link
New issue
Copy link
Open
Open
[Bug]: itertools.groupby group iterator re-entered from the key's __eq__ returns a Java null, which crashes with NullPointerException#1276
Copy link

Description

@taxor03
taxor03
opened on Nov 3, 2026
Issue body actions

Describe the bug

When the key's __eq__ advances the same group iterator while groupby is comparing keys (the case from bpo-30347), the outer next() on the group iterator returns a Java null instead of a value or exhaustion. Using that result terminates the process with a Java NullPointerException (exit status 1). CPython returns None here (the default given to next()).

Operating system

macOS

CPU architecture

ARM64

GraalPy version

25.4.4.1.1 (Python 3.13.14), community build from the GitHub release. The code involved is unchanged on master d0565ae.

JDK version

No response

Context configuration

No response

Steps to reproduce

from itertools import groupby

class K:
    def __init__(self, v):
        pass
    def __eq__(self, other):
        global i
        i += 1
        if i == 1:
            next(g, None)  # advance the same group iterator from inside __eq__
        return True

i = 0
g = next(groupby(range(10), K))[1]
print(repr(next(g, None)))
print(repr(next(g, None)))
print("done")

GraalPy prints 0, then exits with the NullPointerException below.

Expected behavior

CPython 3.13.18 (same on 3.12.16):

0
None
done

Stack trace

java.lang.NullPointerException: Null receiver values are not supported by libraries.
	at org.graalvm.truffle/com.oracle.truffle.api.library.LibraryFactory.dispatch(LibraryFactory.java:550)
	at org.graalvm.truffle/com.oracle.truffle.api.library.LibraryFactory.create(LibraryFactory.java:302)
	at org.graalvm.py/com.oracle.graal.python.nodes.object.GetForeignObjectClassNodeGen.executeAndSpecialize(GetForeignObjectClassNodeGen.java:143)
	at org.graalvm.py/com.oracle.graal.python.nodes.object.GetForeignObjectClassNodeGen.execute(GetForeignObjectClassNodeGen.java:96)
	at org.graalvm.py/com.oracle.graal.python.nodes.object.GetRegisteredClassNode.noRegisteredClass(GetRegisteredClassNode.java:95)
	at org.graalvm.py/com.oracle.graal.python.nodes.object.GetRegisteredClassNodeGen.executeAndSpecialize(GetRegisteredClassNodeGen.java:183)
	at org.graalvm.py/com.oracle.graal.python.nodes.object.GetRegisteredClassNodeGen.execute(GetRegisteredClassNodeGen.java:157)
	at org.graalvm.py/com.oracle.graal.python.nodes.object.GetClassNode.getForeign(GetClassNode.java:200)
	at org.graalvm.py/com.oracle.graal.python.nodes.object.GetClassNodeGen$Inlined.executeAndSpecialize(GetClassNodeGen.java:476)
	at org.graalvm.py/com.oracle.graal.python.nodes.object.GetClassNodeGen$Inlined.execute(GetClassNodeGen.java:393)
	at org.graalvm.py/com.oracle.graal.python.builtins.objects.type.TpSlots$GetObjectSlotsNode.doIt(TpSlots.java:2085)
	at org.graalvm.py/com.oracle.graal.python.builtins.objects.type.TpSlotsFactory$GetObjectSlotsNodeGen$Inlined.execute(TpSlotsFactory.java:342)
	at org.graalvm.py/com.oracle.graal.python.lib.PyObjectReprAsObjectNode.repr(PyObjectReprAsObjectNode.java:105)
	at org.graalvm.py/com.oracle.graal.python.lib.PyObjectReprAsObjectNodeGen$Inlined.execute(PyObjectReprAsObjectNodeGen.java:329)
	at org.graalvm.py/com.oracle.graal.python.builtins.modules.BuiltinFunctions$ReprNode.repr(BuiltinFunctions.java:1711)
	at org.graalvm.py/com.oracle.graal.python.builtins.modules.BuiltinFunctionsFactory$ReprNodeFactory$ReprNodeGen.execute(BuiltinFunctionsFactory.java:7030)

Additional context

Assigning the result instead (x = next(g, None)) does not crash, but x is then unbound: the next line that reads it raises NameError: name 'x' is not defined.

test_itertools.RegressionTests.test_issue30347_2 passes because it discards the result of next(g, None).

Root Cause

GrouperBuiltins.NextNode reads gbo.getCurrValue() after the key comparison (GrouperBuiltins.java#L145-L155). The comparison calls the key's __eq__, and the nested next() there takes the current value and sets it to null, so the outer call returns that null. CPython's _grouper_next also reads currvalue after the comparison, but a NULL return without an exception set means exhaustion there (itertoolsmodule.c#L701-L734).

Fix Suggestion

In NextNode, treat a null current value after the comparison as exhaustion (throw iteratorExhausted()), as CPython does.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.