Problem
Readable local images supplied as standard Path.as_uri() URLs fail to load in the VERL rollout adapter. The loader passes the percent-encoded URI path to Pillow without converting it to a filesystem path. Spaces, Unicode and literal percent signs therefore break image loading; native Windows drive paths also require conversion.
This affects the resulting training data: RolloutAdapter.get_train_data_batch() marks the row for dropping when image processing fails, so an otherwise valid multimodal rollout is removed by the training-row filter.
Minimal reproduction
At d381995396274039f2bb1cbe5ff42ac8067f4e47, with the frozen dev and verl-cpu environment:
from pathlib import Path
from tempfile import TemporaryDirectory
from PIL import Image
from agentlightning.verl.rollout_adapter import _load_pil_image
with TemporaryDirectory() as directory:
path = Path(directory) / "frame 50% 中文.png"
Image.new("RGB", (2, 2), "red").save(path)
with Image.open(path) as image:
assert image.size == (2, 2) # The local file is valid and readable.
image = _load_pil_image(path.as_uri()) # Fails on the encoded/native path.
assert image.size == (2, 2)
I also reproduced the downstream effect through the actual RolloutAdapter.get_train_data_batch() entry point, using Torch CPU, VERL DataProto, and a real Transformers CLIPProcessor with a locally constructed tokenizer and image processor. The same PNG bytes were used for both inputs:
| Input |
is_drop_mask |
Retained rollout IDs |
Pixel tensor shape |
| Base64 data URL |
[false] |
["uri-probe"] |
[1, 3, 2, 2] |
path.as_uri() |
[true] |
[] |
No image input |
No model download, network image request, fake dependency or monkeypatch was used in that comparison.
Expected behavior
Decode the file URI into the platform's native path exactly once before opening the image. The file-URI input should retain the same rollout and image pixels as the data-URL control. Literal encoded-looking filenames such as frame%20.png must not accidentally select a different file named frame .png.
Environment and scope
- Native Windows, Python 3.12.14.
- Agent Lightning 1.0.2 at the commit above; VERL 0.8.0; Torch 2.13.0+cpu; Transformers 5.10.4; Pillow 12.3.0.
- The reproduction exercises the CPU batch adapter, not the local rollout controller or GPU training.
The affected branch is in _load_pil_image. A focused fix with regression tests is in preparation. Investigation and reporting used Codex assistance.
Problem
Readable local images supplied as standard
Path.as_uri()URLs fail to load in the VERL rollout adapter. The loader passes the percent-encoded URI path to Pillow without converting it to a filesystem path. Spaces, Unicode and literal percent signs therefore break image loading; native Windows drive paths also require conversion.This affects the resulting training data:
RolloutAdapter.get_train_data_batch()marks the row for dropping when image processing fails, so an otherwise valid multimodal rollout is removed by the training-row filter.Minimal reproduction
At
d381995396274039f2bb1cbe5ff42ac8067f4e47, with the frozendevandverl-cpuenvironment:I also reproduced the downstream effect through the actual
RolloutAdapter.get_train_data_batch()entry point, using Torch CPU, VERLDataProto, and a real TransformersCLIPProcessorwith a locally constructed tokenizer and image processor. The same PNG bytes were used for both inputs:is_drop_mask[false]["uri-probe"][1, 3, 2, 2]path.as_uri()[true][]No model download, network image request, fake dependency or monkeypatch was used in that comparison.
Expected behavior
Decode the file URI into the platform's native path exactly once before opening the image. The file-URI input should retain the same rollout and image pixels as the data-URL control. Literal encoded-looking filenames such as
frame%20.pngmust not accidentally select a different file namedframe .png.Environment and scope
The affected branch is in
_load_pil_image. A focused fix with regression tests is in preparation. Investigation and reporting used Codex assistance.