Skip to content

Refactor dynamic Scan node lowering - #22758

Merged
rapids-bot[bot] merged 25 commits into
rapidsai:mainfrom
TomAugspurger:tom/dynamic-scan-node-refactor
Jun 4, 2026
Merged

Refactor dynamic Scan node lowering#22758
rapids-bot[bot] merged 25 commits into
rapidsai:mainfrom
TomAugspurger:tom/dynamic-scan-node-refactor

Conversation

@TomAugspurger

@TomAugspurger TomAugspurger commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Description

This refactors how we dynamically generate Scan nodes with the rapidsmpf streaming runtime.

Previously, these nodes were generated inside
cudf_polars.streaming.actor_grpah.io.scan_node. The lowered ir node would have a basic Scan (or maybe a SplitScan node) that was never actually executed. Instead, after we created the Actor responsible for that node, we'd generate new Scan nodes to do the work of reading some subset of the files / row groups.

This PR does the same thing (generate these Scan/SplitScan nodes) but it does it at lowering time, rather than inside the Scan task. The actual logic of generating these new nodes is unchanged. We should end up with exactly the same execution as before; we just make the list[Scan | SplitScan] earlier.

This is primarily motivated by awkwardness in using the dynamically generated Scan nodes in a couple spots:

  1. prefetching parquet metadata(Prefetch parquet metadata for scan tasks #22700)
  2. Quent tracing

I've added a new StreamingScan IR node that just holds references to the list[Scan] nodes. This might be overkill for what we need, but it's at least consistent with how we do the main lowering, which I like.

This refactors how we dynamically generate `Scan` nodes with the
rapidsmpf streaming runtime.

Previously, these nodes were generated inside
`cudf_polars.streaming.actor_grpah.io.scan_node`. Now, we treat it more
like a (rank-specific) lowering stage.

This is primarily motivated by awkwardness in using the dynamically
generated Scan nodes in a couple spots:

1. prefetching parquet metadata(rapidsai#22700)
2. Quent tracing

I've added a new `StreamingScan` IR node that just holds references to
the `list[Scan]` nodes. This might be overkill for what we need, but
it's at least consistent with how we do the main lowering, which I like.
@copy-pr-bot

copy-pr-bot Bot commented Jun 2, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-actions github-actions Bot added Python Affects Python cuDF API. cudf-polars Issues specific to cudf-polars labels Jun 2, 2026
@GPUtester GPUtester moved this to In Progress in cuDF Python Jun 2, 2026
Comment thread python/cudf_polars/cudf_polars/engine/core.py Outdated
Comment thread python/cudf_polars/cudf_polars/engine/core.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/io.py Outdated
@TomAugspurger

Copy link
Copy Markdown
Contributor Author

/ok to test e1a4b4c

@TomAugspurger TomAugspurger added improvement Improvement / enhancement to an existing function non-breaking Non-breaking change labels Jun 3, 2026
@Matt711
Matt711 self-requested a review June 3, 2026 15:09
@TomAugspurger
TomAugspurger requested a review from rjzamora June 3, 2026 15:09
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
This refactors the refactor to just lower to this StreamingScan inside
the the initial lowering.
Comment thread python/cudf_polars/cudf_polars/streaming/io.py Outdated
return new_ir, {new_ir: PartitionInfo(count=count, io_plan=plan)}


class StreamingScan(IR):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we're doing this earlier, I worry that the lack of a StreamingScan.do_evalaute is going to cause issues. Like, how would the in-memory executor handle this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this PR should just ago a bit further? Maybe we don't really want StreamingScan to carry around a list[Scan | SplitScan]. Rather, we just collect list[ScanChunkInfo], where:

class ScanChunkInfo:
    paths: list[str]
    """List of paths to read from"""
    chunk_index: int
    """Index of this chunk (within `paths`)"""
    num_chunks: int
    """Total number of chunks being generated from `paths`"""

This way, we can add a StreamingScan.do_evaluate that basically looks like SplitScan.do_evaluate (but is actually simpler when len(paths) > 1, because num_chunks is always 1 in that case).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking a look, but can you say a bit more about why avoiding Scan / SplitScan instances might be desirable here?

I'm looking at

async def _producer(producer_id: int, ch_out: Channel) -> None:
for task_idx, ir_slice in producer_tasks[producer_id]:
await read_chunk(
context,
ir_slice,
task_idx,
ch_out,
ir_context,
estimated_chunk_bytes,
tracer=tracer,
)
, which I think would need to change. That calls read_chunk on the Scan / SplitScan that were previously dynamically generated.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you say a bit more about why avoiding Scan / SplitScan instances might be desirable here?

I may be wrong, but it seems like you are running into issues with the misdirection between the Scan node in the plan and the actual Scan/SplitScan IR objects that are used in the actor. I'm just pointing out that we don't actually need to create a bunch of independent Scan/SplitScan objects if that's an issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. I think it's less about whether or not the Scan nodes are created, and more about when they're created.

In #22700, we want to know all of the parquet paths we're going to read (on each worker) before we start reading any data. I think as long as we create these nodes ahead of time then we're OK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, yeah. That's all completely up to us.

The only explicit design choice we probably want to commit to is the idea that we don't need to parse all Parquet metadata up-front to make the general partitioning plan.

Some unnecessary background (feel free to ignore if irrelevant):

This was a mistake that we made in Dask-DataFrame read_parquet API several years ago: We needed to specify specific path and row-group indeices for every read task in order to build the task graph. That ended up being terrible for cloud IO, because we would need to parse all footer metadata up front. The cudf-polars design is different. We either expect each chunk to be a range of complete files, or we expect each chunk to be a slice of a single file. For the latter case, we don't need to know exactly which row-groups a specific chunk will be mapped to ahead of time. We just need to know how many chunks will be mapped from that file. The specific row-group range can be determined by the actor at runtime when the footer metadata for that file is already available.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think that aligns with my goals. With this and #22700, we should read each file metadata at most once per worker, and we should only read the file metadata of files we actually are responsible for reading.

@TomAugspurger
TomAugspurger marked this pull request as ready for review June 3, 2026 17:39
@TomAugspurger
TomAugspurger requested a review from a team as a code owner June 3, 2026 17:39
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR threads rank/nranks through IR lowering, adds expand_scan_for_rank and a StreamingScan IR to produce rank-local scan lists, updates the actor graph to consume StreamingScan (including native-parquet gating and simplified scan_node), extends serialization and fast-count paths, and adds unit and integration tests.

Changes

Rank-aware Streaming IO

Layer / File(s) Summary
Rank parameter propagation through lowering pipeline
python/cudf_polars/cudf_polars/engine/core.py, python/cudf_polars/cudf_polars/streaming/parallel.py, python/cudf_polars/cudf_polars/streaming/dispatch.py
evaluate_on_rank passes rank and nranks from the communicator into lower_ir_graph. lower_ir_graph signature and docstring accept *, rank: int = 0, nranks: int = 1. Internal lowering State now includes rank and nranks.
Scan expansion and StreamingScan IR
python/cudf_polars/cudf_polars/streaming/io.py
Adds expand_scan_for_rank to expand a Scan into rank-local Scan/SplitScan items per IOPartitionPlan flavor, introduces should_use_native_parquet_node, adjusts parquet_options as needed, wraps expanded scans in a new StreamingScan IR node, and returns PartitionInfo/io_plan.
Actor graph scan pipeline updates
python/cudf_polars/cudf_polars/streaming/actor_graph/core.py, python/cudf_polars/cudf_polars/streaming/actor_graph/io.py
Registers StreamingScan as an IO node (affecting IO thread sizing), updates imports, switches scan sub-network registration to StreamingScan, updates scan_node to consume ir.scans (pre-built scans), gates native read fast path on ir.base_scan, and simplifies fallback wiring.
Query serialization and fast-count optimization
python/cudf_polars/cudf_polars/streaming/explain.py, python/cudf_polars/cudf_polars/streaming/select.py
Adds _serialize_properties handler for StreamingScan (serializes typ, scan_count, prefix, optional predicate) and updates fast-count path to handle StreamingScan by using child.base_scan, preserving legacy Scan handling.
Scan expansion unit tests and integration tests
python/cudf_polars/tests/streaming/test_scan.py, python/cudf_polars/tests/streaming/test_explain.py
Test imports updated for expansion utilities. Adds _make_parquet_scan, test_scan_join, test_scan_union, parametrized test_expand_scan_for_rank_fused_and_single_read, and test_expand_scan_for_rank_split_files. Updates explain test expectations for StreamingScan and scan_count.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • Matt711
  • wence-
  • rjzamora
  • mroeschke
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Refactor dynamic Scan node lowering' directly matches the main change: moving Scan node generation from actor creation time to an earlier rank-specific lowering stage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description clearly explains the refactoring of dynamic Scan node generation, moving the logic from actor task time to lowering time, and introduces the StreamingScan IR node with specific motivations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/core.py Outdated
return new_ir, {new_ir: PartitionInfo(count=count, io_plan=plan)}


class StreamingScan(IR):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this PR should just ago a bit further? Maybe we don't really want StreamingScan to carry around a list[Scan | SplitScan]. Rather, we just collect list[ScanChunkInfo], where:

class ScanChunkInfo:
    paths: list[str]
    """List of paths to read from"""
    chunk_index: int
    """Index of this chunk (within `paths`)"""
    num_chunks: int
    """Total number of chunks being generated from `paths`"""

This way, we can add a StreamingScan.do_evaluate that basically looks like SplitScan.do_evaluate (but is actually simpler when len(paths) > 1, because num_chunks is always 1 in that case).

@TomAugspurger

Copy link
Copy Markdown
Contributor Author

The fallback chunked=False override no longer takes effect.

I'm looking into this. It's certainly correct that the parquet_options = dataclasses.replace(parquet_options, chunked=False) now has no effect. And I think it's correct that the Scan nodes that were previously generated with chunked=False no longer have that. But I want to understand why we have this in the first place.

@TomAugspurger

Copy link
Copy Markdown
Contributor Author

b8ca40e attempts to fix that "chunked=False fallback" thing, without really understanding the issue. I'm just trying to replicate the old behavior here.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
python/cudf_polars/cudf_polars/streaming/io.py (1)

477-496: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix StreamingScan _non_child / __init__ argument mismatch to avoid pickling/reconstruct TypeError
Node.__reduce__/reconstruct build constructor args from StreamingScan._non_child in-order (scans, base_scan, schema), but StreamingScan.__init__ currently only accepts (scans, base_scan), so reconstruction (e.g. Dask/Ray pickling) would call the constructor with 3 positional args and raise TypeError. Align _non_child with the constructor signature (and update the new_ir = StreamingScan(scans, ir) call-site accordingly).

🐛 Proposed fix — make schema a constructor arg
     _non_child = (
+        "schema",
         "scans",
         "base_scan",
-        "schema",
     )
-    _n_non_child_args = 2
+    _n_non_child_args = 3
     scans: list[Scan | SplitScan]
     base_scan: Scan

-    def __init__(self, scans: list[Scan | SplitScan], base_scan: Scan):
+    def __init__(self, schema: Schema, scans: list[Scan | SplitScan], base_scan: Scan):
         self.scans = scans
         self.base_scan = base_scan
-        self.schema = base_scan.schema
-        self._non_child_args = (scans, base_scan)
+        self.schema = schema
+        self._non_child_args = (schema, scans, base_scan)
         self.children = ()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cudf_polars/cudf_polars/streaming/io.py` around lines 477 - 496,
StreamingScan's _non_child lists ("scans", "base_scan", "schema") but __init__
only accepts (scans, base_scan), causing reconstruct/pickling to pass three
positional args and raise TypeError; change StreamingScan.__init__ to accept a
third parameter (schema) and set self.schema from that param, update
_n_non_child_args to 3, keep _non_child in the declared order, and update
call-sites such as the new_ir = StreamingScan(scans, ir) invocation to pass the
schema (e.g., StreamingScan(scans, ir, ir.schema)) so construction and
Node.__reduce__/reconstruct ordering match.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@python/cudf_polars/cudf_polars/streaming/io.py`:
- Around line 477-496: StreamingScan's _non_child lists ("scans", "base_scan",
"schema") but __init__ only accepts (scans, base_scan), causing
reconstruct/pickling to pass three positional args and raise TypeError; change
StreamingScan.__init__ to accept a third parameter (schema) and set self.schema
from that param, update _n_non_child_args to 3, keep _non_child in the declared
order, and update call-sites such as the new_ir = StreamingScan(scans, ir)
invocation to pass the schema (e.g., StreamingScan(scans, ir, ir.schema)) so
construction and Node.__reduce__/reconstruct ordering match.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b0416e34-b2a6-4d24-9031-7900f6dbbe0c

📥 Commits

Reviewing files that changed from the base of the PR and between b8ca40e and 5782448.

📒 Files selected for processing (2)
  • python/cudf_polars/cudf_polars/streaming/actor_graph/io.py
  • python/cudf_polars/cudf_polars/streaming/io.py

@Matt711 Matt711 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ended up being very clean, thanks!

Comment thread python/cudf_polars/cudf_polars/streaming/actor_graph/io.py Outdated
Comment thread python/cudf_polars/tests/streaming/test_scan.py
Comment thread python/cudf_polars/tests/streaming/test_scan.py Outdated
Comment thread python/cudf_polars/cudf_polars/streaming/io.py Outdated
Comment thread python/cudf_polars/tests/test_scan.py Outdated
@TomAugspurger

Copy link
Copy Markdown
Contributor Author

/merge

@TomAugspurger

TomAugspurger commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

Some failures in the polars tests:

2026-06-04T16:10:33.4581113Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_collapse[True-False-col1-col1] - hypothesis.errors.FlakyFailure: Inconsistent results from replaying a test case!
2026-06-04T16:10:33.4581633Z   last: INTERESTING from MemoryError at /pyenv/versions/3.14.5/lib/python3.14/site-packages/cudf_polars/engine/core.py:483
2026-06-04T16:10:33.4582080Z     context: ExceptionGroup at /pyenv/versions/3.14.5/lib/python3.14/asyncio/taskgroups.py:174
2026-06-04T16:10:33.4582393Z         child exceptions:
2026-06-04T16:10:33.4582823Z           ExceptionGroup at /pyenv/versions/3.14.5/lib/python3.14/asyncio/taskgroups.py:174
2026-06-04T16:10:33.4583128Z             child exceptions:
2026-06-04T16:10:33.4583463Z               MemoryError at pylibcudf/table.pyx:196
2026-06-04T16:10:33.4583896Z               MemoryError at pylibcudf/table.pyx:196
2026-06-04T16:10:33.4584441Z   this: INTERESTING from MemoryError at /pyenv/versions/3.14.5/lib/python3.14/site-packages/cudf_polars/engine/core.py:483
2026-06-04T16:10:33.4584885Z     context: ExceptionGroup at /pyenv/versions/3.14.5/lib/python3.14/asyncio/taskgroups.py:174
2026-06-04T16:10:33.4585181Z         child exceptions:
2026-06-04T16:10:33.4585608Z           ExceptionGroup at /pyenv/versions/3.14.5/lib/python3.14/asyncio/taskgroups.py:174
2026-06-04T16:10:33.4585902Z             child exceptions:
2026-06-04T16:10:33.4586259Z               MemoryError at pylibcudf/table.pyx:196 (3 sub-exceptions)
2026-06-04T16:10:33.4587536Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_collapse[True-True-col0-col0] - ExceptionGroup: Hypothesis found 2 distinct failures. (2 sub-exceptions)
2026-06-04T16:10:33.4588198Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_collapse[True-True-col0-col1] - ExceptionGroup: Hypothesis found 2 distinct failures. (2 sub-exceptions)
2026-06-04T16:10:33.4588888Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_collapse[True-True-col1-col0] - hypothesis.errors.FlakyFailure: Inconsistent results from replaying a test case!
2026-06-04T16:10:33.4589676Z   last: INTERESTING from MemoryError at /pyenv/versions/3.14.5/lib/python3.14/site-packages/cudf_polars/engine/core.py:483
2026-06-04T16:10:33.4590117Z     context: ExceptionGroup at /pyenv/versions/3.14.5/lib/python3.14/asyncio/taskgroups.py:174
2026-06-04T16:10:33.4590422Z         child exceptions:
2026-06-04T16:10:33.4590827Z           ExceptionGroup at /pyenv/versions/3.14.5/lib/python3.14/asyncio/taskgroups.py:174
2026-06-04T16:10:33.4591123Z             child exceptions:
2026-06-04T16:10:33.4591450Z               MemoryError at pylibcudf/scalar.pyx:524
2026-06-04T16:10:33.4592076Z   this: INTERESTING from MemoryError at /pyenv/versions/3.14.5/lib/python3.14/site-packages/cudf_polars/engine/core.py:483
2026-06-04T16:10:33.4592509Z     context: ExceptionGroup at /pyenv/versions/3.14.5/lib/python3.14/asyncio/taskgroups.py:174
2026-06-04T16:10:33.4592799Z         child exceptions:
2026-06-04T16:10:33.4593316Z           AssertionError at /pyenv/versions/3.14.5/lib/python3.14/site-packages/cudf_polars/streaming/actor_graph/utils.py:379
2026-06-04T16:10:33.4593833Z           ExceptionGroup at /pyenv/versions/3.14.5/lib/python3.14/asyncio/taskgroups.py:174
2026-06-04T16:10:33.4594123Z             child exceptions:
2026-06-04T16:10:33.4594487Z               MemoryError at pylibcudf/scalar.pyx:524 (3 sub-exceptions)
2026-06-04T16:10:33.4595316Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_collapse[True-True-col1-col1] - RuntimeError: CUDA error at: /__w/rmm/rmm/cpp/src/cuda_stream_view.cpp:45: cudaErrorIllegalAddress an illegal memory access was encountered
...
2026-06-04T16:10:33.4604946Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_collapse_multiple[False] - MemoryError: Try lowering `target_partition_size` (current 10) and/or RAPIDSMPF_SPILL_DEVICE_LIMIT (default '80%') to reduce peak memory.
2026-06-04T16:10:33.4605413Z See https://docs.rapids.ai/api/cudf/stable/cudf_polars/memory_errors/ for troubleshooting guidance.
2026-06-04T16:10:33.4605697Z Original error:
2026-06-04T16:10:33.4606360Z std::bad_alloc: CUDA error (failed to allocate 24 bytes) at: /__w/rmm/rmm/cpp/src/mr/cuda_async_view_memory_resource.cpp:43: cudaErrorIllegalAddress an illegal memory access was encountered
2026-06-04T16:10:33.4607983Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_collapse_multiple[True] - MemoryError: Try lowering `target_partition_size` (current 10) and/or RAPIDSMPF_SPILL_DEVICE_LIMIT (default '80%') to reduce peak memory.
2026-06-04T16:10:33.4608446Z See https://docs.rapids.ai/api/cudf/stable/cudf_polars/memory_errors/ for troubleshooting guidance.
2026-06-04T16:10:33.4608734Z Original error:
2026-06-04T16:10:33.4609380Z std::bad_alloc: CUDA error (failed to allocate 24 bytes) at: /__w/rmm/rmm/cpp/src/mr/cuda_async_view_memory_resource.cpp:43: cudaErrorIllegalAddress an illegal memory access was encountered
2026-06-04T16:10:33.4610033Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_prune_hint[False-col0-col0] - ExceptionGroup: Hypothesis found 4 distinct failures. (4 sub-exceptions)
2026-06-04T16:10:33.4610804Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_prune_hint[False-col0-col1] - ExceptionGroup: Hypothesis found 4 distinct failures. (4 sub-exceptions)
2026-06-04T16:10:33.4611464Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_prune_hint[False-col1-col0] - ExceptionGroup: Hypothesis found 2 distinct failures. (2 sub-exceptions)
2026-06-04T16:10:33.4612098Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_prune_hint[False-col1-col1] - ExceptionGroup: Hypothesis found 4 distinct failures. (4 sub-exceptions)
2026-06-04T16:10:33.4612724Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_prune_hint[True-col0-col0] - ExceptionGroup: Hypothesis found 4 distinct failures. (4 sub-exceptions)
2026-06-04T16:10:33.4613503Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_prune_hint[True-col0-col1] - ExceptionGroup: Hypothesis found 3 distinct failures. (3 sub-exceptions)
2026-06-04T16:10:33.4614266Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_prune_hint[True-col1-col0] - ExceptionGroup: Hypothesis found 2 distinct failures. (2 sub-exceptions)
2026-06-04T16:10:33.4614919Z FAILED py-polars/tests/unit/lazyframe/test_sort_collapse.py::test_sort_node_prune_hint[True-col1-col1] - ExceptionGroup: Hypothesis found 4 distinct failures. (4 sub-exceptions)
2026-06-04T16:10:33.4615682Z FAILED py-polars/tests/unit/lazyframe/test_with_context.py::test_with_context_ignore_5867 - MemoryError: Try lowering `target_partition_size` (current 10) and/or RAPIDSMPF_SPILL_DEVICE_LIMIT (default '80%') to reduce peak memory.
2026-06-04T16:10:33.4616132Z See https://docs.rapids.ai/api/cudf/stable/cudf_polars/memory_errors/ for troubleshooting guidance.
2026-06-04T16:10:33.4616950Z Original error:
2026-06-04T16:10:33.4617621Z std::bad_alloc: CUDA error (failed to allocate 16 bytes) at: /__w/rmm/rmm/cpp/src/mr/cuda_async_view_memory_resource.cpp:43: cudaErrorIllegalAddress an illegal memory access was encountered
2026-06-04T16:10:33.4618339Z FAILED py-polars/tests/unit/meta/test_api.py::test_custom_lazy_namespace - MemoryError: Try lowering `target_partition_size` (current 10) and/or RAPIDSMPF_SPILL_DEVICE_LIMIT (default '80%') to reduce peak memory.
2026-06-04T16:10:33.4618797Z See https://docs.rapids.ai/api/cudf/stable/cudf_polars/memory_errors/ for troubleshooting guidance.
2026-06-04T16:10:33.4619079Z Original error:
2026-06-04T16:10:33.4619741Z std::bad_alloc: CUDA error (failed to allocate 64 bytes) at: /__w/rmm/rmm/cpp/src/mr/cuda_async_view_memory_resource.cpp:43: cudaErrorIllegalAddress an illegal memory access was encountered
2026-06-04T16:10:33.4620565Z FAILED py-polars/tests/unit/operations/aggregation/test_aggregations.py::test_string_par_materialize_8207 - MemoryError: Try lowering `target_partition_size` (current 10) and/or RAPIDSMPF_SPILL_DEVICE_LIMIT (default '80%') to reduce peak memory.
2026-06-04T16:10:33.4621015Z See https://docs.rapids.ai/api/cudf/stable/cudf_polars/memory_errors/ for troubleshooting guidance.
2026-06-04T16:10:33.4621292Z Original error:
2026-06-04T16:10:33.4621976Z std::bad_alloc: CUDA error (failed to allocate 64 bytes) at: /__w/rmm/rmm/cpp/src/mr/cuda_async_view_memory_resource.cpp:43: cudaErrorIllegalAddress an illegal memory access was encountered
2026-06-04T16:10:33.4622976Z FAILED py-polars/tests/unit/operations/aggregation/test_aggregations.py::test_online_variance - MemoryError: Try lowering `target_partition_size` (current 10) and/or RAPIDSMPF_SPILL_DEVICE_LIMIT (default '80%') to reduce peak memory.
2026-06-04T16:10:33.4623440Z See https://docs.rapids.ai/api/cudf/stable/cudf_polars/memory_errors/ for troubleshooting guidance.
2026-06-04T16:10:33.4623826Z Original error:
2026-06-04T16:10:33.4630597Z std::bad_alloc: CUDA error (failed to allocate 8 bytes) at: /__w/rmm/rmm/cpp/src/mr/cuda_async_view_memory_resource.cpp:43: cudaErrorIllegalAddress an illegal memory access was encountered
2026-06-04T16:10:33.4631634Z FAILED py-polars/tests/unit/operations/aggregation/test_aggregations.py::test_mapped_literal_to_literal_9217 - MemoryError: Try lowering `target_partition_size` (current 10) and/or RAPIDSMPF_SPILL_DEVICE_LIMIT (default '80%') to reduce peak memory.
2026-06-04T16:10:33.4632103Z See https://docs.rapids.ai/api/cudf/stable/cudf_polars/memory_errors/ for troubleshooting guidance.
2026-06-04T16:10:33.4632399Z Original error:
2026-06-04T16:10:33.4633078Z std::bad_alloc: CUDA error (failed to allocate 1 bytes) at: /__w/rmm/rmm/cpp/src/mr/cuda_async_view_memory_resource.cpp:43: cudaErrorIllegalAddress an illegal memory access was encountered
2026-06-04T16:10:33.4633994Z FAILED py-polars/tests/unit/operations/aggregation/test_aggregations.py::test_sum_empty_and_null_set - MemoryError: Try lowering `target_partition_size` (current 10) and/or RAPIDSMPF_SPILL_DEVICE_LIMIT (default '80%') to reduce peak memory.
2026-06-04T16:10:33.4634584Z See https://docs.rapids.ai/api/cudf/stable/cudf_polars/memory_errors/ for troubleshooting guidance.
2026-06-04T16:10:33.4634880Z Original error:

At least some of these are consistent with the node just being out of GPU memory unexpectedly.

@Matt711

Matt711 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Maybe just rerun since the other job passed?

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

Labels

cudf-polars Issues specific to cudf-polars improvement Improvement / enhancement to an existing function non-breaking Non-breaking change Python Affects Python cuDF API.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

5 participants