huggingface / huggingface/diffusers
InpaintProcessor.preprocess returns a bare tensor when no mask is passed, breaking its own 3-value contract
- Dominant language
- Python
- Stars
- 34.5k
- Forks
- 7.3k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 91
Description
### Describe the bug
`InpaintProcessor.preprocess` returns `(image, mask, postprocessing_kwargs)` on every path except the `mask is None` early return ([`image_processor.py#L895-L897`](https://github.com/huggingface/diffusers/blob/main/src/diffusers/image_processor.py#L895-L897)), which returns the processed image on its own. Unpacking the three values the rest of the method promises then raises:
```
ValueError: not enough values to unpack (expected 3, got 1)
```
The return annotation is `tuple[torch.Tensor, torch.Tensor]`, which no path actually returns, every masked path returns three values.
Both the early return and the three-value contract were introduced in the same commit (`f50b18eec`, #12220), so this looks like the early return simply not being updated when `postprocessing_kwargs` was added, rather than an intentional two-shape API.
Both in-repo call sites unpack three values (`modular_pipelines/qwenimage/encoders.py#L1144` and `#L1236`), but their `mask_image` input is `required=True`, so they never reach the branch. It is reachable through direct use of `InpaintProcessor`, which is exported from `diffusers` and documented in `docs/source/en/api/image_processor.md`.
### Reproduction
```python
import numpy as np
import PIL.Image
from diffusers.image_processor import InpaintProcessor
image = PIL.Image.fromarray(np.zeros((64, 64, 3), dtype=np.uint8))
mask = PIL.Image.fromarray(np.zeros((64, 64), dtype=np.uint8))
processor = InpaintProcessor()
print(len(processor.preprocess(image, mask=mask, height=64, width=64))) # 3
print(type(processor.preprocess(image, height=64, width=64))) #
img, msk, kwargs = processor.preprocess(image, height=64, width=64)
```
Output:
```
3
Traceback (most recent call last):
...
ValueError: not enough values to unpack (expected 3, got 1)
```
### Logs
```shell
```
### System Info
- 🤗 Diffusers version: 0.40.0.dev0 (`main`)
- Platform: macOS-26.6-arm64-arm-64bit-Mach-O
- Python version: 3.13.7
- PyTorch version (GPU?): 2.13.0 (False)
- Huggingface_hub version: 1.27.0
- Safetensors version: 0.8.0
- Accelerator: Apple M3
- Using GPU in script?: No
- Using distributed or parallel set-up in script?: No
### Who can help?
@DN6 @yiyixuxu
Contributor guide
Research direction
Start in src/diffusers/image_processor.py around lines 895-897 and compare the no-mask path with the masked returns. Check the unpacking call sites in modular_pipelines/qwenimage/encoders.py and the API documentation in docs/source/en/api/image_processor.md. Done means InpaintProcessor.preprocess has one consistent three-value contract and the reproduction no longer raises when mask is omitted.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, pytorch
- Domain
- computer-vision, machine-learning
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100