Skip to content

Fix silent dataset truncation in batched map with mismatched empty column (#6879)#8311

Open
florian6973 wants to merge 1 commit into
huggingface:mainfrom
florian6973:fix/6879-batched-map-empty-column-silent-truncation
Open

Fix silent dataset truncation in batched map with mismatched empty column (#6879)#8311
florian6973 wants to merge 1 commit into
huggingface:mainfrom
florian6973:fix/6879-batched-map-empty-column-silent-truncation

Conversation

@florian6973

Copy link
Copy Markdown

What does this PR do?

Fixes #6879.

Dataset.map(fn, batched=True) silently truncates the dataset to 0 rows (instead of raising) when the mapping function empties an existing column while another column stays non-empty.

Reproducer (from the issue)

import datasets
data = datasets.Dataset.from_dict({"test": [1]})

def mapping_fn(examples):
    return {"test": [], "y": [1]}

data = data.map(mapping_fn, batched=True)
print(len(data))   # 0  -> silent data loss

Returning an empty list for a new column (e.g. {"x": []}) already raises pyarrow.lib.ArrowInvalid, so the two cases were inconsistent.

Root cause

ArrowWriter._write_batch skips a batch that "appears empty", but the emptiness check only looked at the first column:

if batch_examples and len(next(iter(batch_examples.values()))) == 0:
    return

When a batched map overwrites an existing column with [], that column stays first in the merged dict, so the whole length-mismatched batch was dropped instead of erroring.

Fix

Skip the batch only when every column is empty. Genuinely empty batches (e.g. a batch that filters out all its rows) are still ignored, while mismatched batches now fall through to pa.Table.from_arrays, which raises the same informative ArrowInvalid already produced for the new-column case.

if batch_examples and all(len(col_values) == 0 for col_values in batch_examples.values()):
    return

Behavior

issue reproducer
before no exception, len(data) == 0
after ArrowInvalid: Column 1 named y expected length 0 but got length 1

Normal batched map and legitimate "all columns empty" batches are unchanged.

Tests

Added test_write_batch_with_mismatched_empty_column_raises in tests/test_arrow_writer.py. The existing test_write_batch already covers the legitimate all-empty-batch skip, so that path stays protected.

ruff check / ruff format --check pass; tests/test_arrow_writer.py passes locally.

…lumn (huggingface#6879)

`ArrowWriter._write_batch` skips a batch when it "appears empty", but the
emptiness check only looked at the first column's length. When a batched
`map` function returns an empty list for an existing column alongside a
non-empty column (e.g. `{"test": [], "y": [1]}`), the first column being
empty caused the whole length-mismatched batch to be silently dropped,
truncating the dataset to 0 rows instead of raising.

Skip the batch only when *all* columns are empty, so genuinely empty
batches are still ignored (unchanged behavior, covered by the existing
`test_write_batch`) while mismatched batches fall through to
`pa.Table.from_arrays`, which raises the informative `ArrowInvalid`
already produced for the new-column case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@florian6973 florian6973 marked this pull request as ready for review July 7, 2026 23:32
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.

Batched mapping does not raise an error if values for an existing column are empty

1 participant