Skip to content

[Bug]: aiter() raises async for-specific TypeError message instead of CPython's #753

@jseop-lim

Description

@jseop-lim

Description

When aiter() is called with an object that lacks __aiter__, GraalPy raises TypeError with the message 'async for' requires object with __aiter__ method, got NoneType. CPython raises the same exception type with a different, builtin-specific message: 'NoneType' object is not an async iterable. This is a CPython compatibility issue.

Root Cause

The aiter() builtin in BuiltinFunctions.AIter delegates to GetAIterNode, which is the node used by the async for statement. GetAIterNode raises the async for-specific message ASYNC_FOR_NO_AITER ('async for' requires object with __aiter__ method, got %N), so the builtin leaks an async for-themed message to users who never wrote async for.

CPython keeps the two paths separate: async for goes through the GET_AITER opcode while builtin_aiter calls PyObject_GetAIter, which produces a distinct, object-centric message.

CPython reference: Objects/abstract.c#L2801-L2817

// PyObject_GetAIter raises a builtin-specific message (distinct from the
// GET_AITER opcode used by `async for`) when am_aiter is not implemented.
PyObject *
PyObject_GetAIter(PyObject *o) {
    PyTypeObject *t = Py_TYPE(o);
    if (t->tp_as_async == NULL || t->tp_as_async->am_aiter == NULL) {
        return type_error("'%.200s' object is not an async iterable", o);
    }
    ...
}

Note that GraalPy's own C-API port at com.oracle.graal.python.cext/src/abstract.c already uses the CPython message — only the Java-side builtin entry point reuses the async for node and inherits its message.

Fix

Make AIter replicate PyObject_GetAIter inline (check am_aiter slot, call it, verify the result with PyAIterCheckNode) and add a dedicated NOT_AN_ASYNC_ITERABLE error message, instead of delegating to GetAIterNode.

Reproduction

aiter(None)

Output

GraalPy:

TypeError: 'async for' requires object with __aiter__ method, got NoneType

CPython:

TypeError: 'NoneType' object is not an async iterable

Environment

  • GraalPy 25.0.2 (Python 3.12.8)
  • CPython 3.12.13
  • OS: Debian 12

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions