mp_prefetch silently drops elements that cannot be pickled
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 78/100
Research direction
Start in grain/_src/python/ipc/queue.py at add_element_to_queue, where multiprocessing.Queue.put returns before the feeder thread pickles; then read _put_dataset_elements_in_buffer in process_prefetch.py to see how the existing error tuple is produced and later raised by __next__. Pickle the element in the worker before putting it (see _check_picklable / _serialize_dataset for prior art) and route a failure through that error tuple. Done when the repro's unpicklable element makes iteration raise instead of silently dropping the item, covered by a test running mp_prefetch with one worker.
Written by the indexing model from the issue text.
Description
mp_prefetch silently drops any element that cannot be pickled. Iteration ends normally with that element missing: no exception reaches the caller, and the only trace is a traceback printed by a background thread.
Repro
import grain
import numpy as np
from absl import flags
def element(i):
# Element 2 carries a value that pickle cannot serialise.
extra = (lambda: i) if i == 2 else i
return np.full(4, i), {"extra": extra}
if __name__ == "__main__":
flags.FLAGS.mark_as_parsed() # see google/grain#1411
ds = grain.MapDataset.range(5).map(element).to_iter_dataset()
ds = ds.mp_prefetch(grain.multiprocessing.MultiprocessingOptions(num_workers=1))
print("served:", [int(x[0]) for x, _ in ds])
uv run --isolated --no-project --python 3.12 --with grain==0.2.18 python repro.py
Output (exit code 0), the same with or without --with jax:
Traceback (most recent call last):
File ".../multiprocessing/queues.py", line 264, in _feed
obj = _ForkingPickler.dumps(obj)
File ".../multiprocessing/reduction.py", line 51, in dumps
cls(buf, protocol).dump(obj)
AttributeError: Can't get local object 'element.<locals>.<lambda>'
served: [0, 1, 3, 4]
Expected: an exception at the element that cannot be sent (or at least not a silent gap). With every element unpicklable, the iterator yields nothing and still exits normally. The same happens with 2 workers.
Cause
The worker puts each element with grain_queue.add_element_to_queue (grain/_src/python/ipc/queue.py), which calls multiprocessing.Queue.put and returns True. multiprocessing.Queue pickles in its feeder thread after put has returned, so a pickling error there is only printed and the item is dropped. The worker loop (process_prefetch.py, _put_dataset_elements_in_buffer) carries on, and the parent receives the remaining elements and then StopIteration.
Grain already checks that the dataset pickles before starting workers (_check_picklable / _serialize_dataset), but nothing checks an element. The put path is the same at v0.2.18 and current main.
One possible fix: pickle the element in the worker before put (or send it as bytes) and route a failure through the existing error tuple, so __next__ raises it the way it raises other worker errors.
Environment: grain 0.2.18, Python 3.12, Linux x86_64.
- Dominant language
- Python
- Stars
- 792
- Forks
- 89
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 15
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from google/grain
-
ConcatThenSplitIterDataset drops a document when restored from a JSON-serialized statePossibly taken @AshishKumar4 claimed this 4 days ago. Opentype:bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
Closing an mp_prefetch iterator stops its worker processes one at a timePossibly taken @jabrailkhalil claimed this 10 days ago. Opentype:bug
Difficulty 2/5 1-3 hours Newbie friendliness 83/100
Maintainers usually reply within 1 day
-
WindowShuffleMapDataset duplicates and omits records in incomplete windowsPossibly taken @salma2vec claimed this 2 days ago. Opentype:bug
Difficulty 3/5 1-2 days Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
`stats._iter_weakref_registry` keeps refs of dead iterators, and a new iterator at a reused address is not registeredPossibly taken @Shr3yash claimed this 11 days ago. Opentype:bug
Difficulty 3/5 Half a day Newbie friendliness 55/100
Maintainers usually reply within 1 day
-
type:bug
Difficulty 4/5 3-5 days Newbie friendliness 25/100
Maintainers usually reply within 1 day
Similar issues
-
Python Volcengine provider returns failures instead of raising themPossibly taken @Ricardo-M-L claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 79/100
agent-infra/sandbox#248 ·
-
Textractor leaves empty temporary files when remote retrieval failsPossibly taken @HuaTNA claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
test(bm_generation): pin the learning parameters and CPU sync shortcutPossibly taken @iloveeyjafjalla claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
qboson/kaiwu-pytorch-plugin#1341 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
elder-plinius/V3R1T4S#625 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
foxglove/mcap#1907 · 1 comment ·
Maintainers usually reply within 1 day