Fixing Corrupted ComfyUI Upscale Output on Mac MPS with contiguous()
Contents
I was batch-upscaling 640px images from AntiGravity in ComfyUI when some outputs came out completely garbled. I initially suspected an upscaler model compatibility issue, but the real cause turned out to be a memory layout problem much further upstream.
2026-04-29 update: A ComfyUI update predictably wiped this patch and the bug came back. Reapplying the same one-liner fixed it again, and along the way I found the upstream PyTorch issue (#169342), so I appended the recurrence story, the diagnostic shortcut, and a small ops snippet to detect the patch going missing after future updates.
What Was Happening
The conditions to reproduce it were:
- Mac (Apple Silicon)
- ComfyUI’s
Upscale Image (using Model)node - Input image coming straight from a
Load Imagenode
Oddly, images generated within ComfyUI’s own pipeline rarely got corrupted — only Load Image as the source caused the problem. Tracking down that difference made the culprit clear.
Root Cause
ComfyUI image tensors are natively in BHWC format. The Upscale node internally permutes them to BCHW before passing to ESRGAN-family models.
After this permutation, the tensor can end up non-contiguous, and passing it directly to conv2d on MPS breaks things.
The specific issue: tiled_scale_multidim was passing s_in, a narrow() slice, directly to function(s_in) without making it contiguous first.
The Fix
One line changed in comfy/utils.py:
# before
ps = function(s_in).to(output_device)
# after
ps = function(s_in.contiguous()).to(output_device)
That single line fixed the corrupted output.
Related issue — still open at the time of writing:
https://github.com/comfyanonymous/ComfyUI/issues/11851
How to Apply the Patch
cd ~/ComfyUI
source venv/bin/activate
# Back up just in case
cp comfy/utils.py comfy/utils.py.bak
# Edit the file and replace:
# ps = function(s_in).to(output_device)
# with:
# ps = function(s_in.contiguous()).to(output_device)
# Restart ComfyUI
python main.py
Notes
--force-fp32 and PYTORCH_ENABLE_MPS_FALLBACK=0 were useful for narrowing things down, but precision settings weren’t the real issue here — memory layout was.
So “MPS breaks it” isn’t quite accurate. A more precise description would be: “paths that encounter a non-contiguous input tend to break on MPS.”
Maintenance Note
Manual edits to comfy/utils.py get overwritten when you update ComfyUI. If the problem comes back after an update, reapply the same one-liner.
If you see similar corruption from Sharpen or other nodes that do BHWC -> BCHW conversion, inserting .contiguous() right after permute/movedim should prevent recurrence.
2026-04-29 Update: It Came Back
I was running a manga-style monochrome workflow (color image → optional background removal → grayscale + halftone + line art extraction → 4x-UltraSharp upscale) when the upscaled output collapsed into horizontal noise. Everything upstream looked fine — only the ImageUpscaleWithModel output was dead.
| Node [42] (right after 4x-UltraSharp) | Final output [54] |
|---|---|
![]() | ![]() |
The full workflow (FireShot screenshot):

The upstream PyTorch issue exists now
In February I only had ComfyUI’s issue #11851. There’s now a proper upstream report on the PyTorch side too:
pytorch/pytorch #169342 — MPS chunk view + conv produces incorrect results (filed 2025-12, still open as of 2026-04)
tensor views created by
chunk()produce incorrect results when passed through convolution operations
It’s not just chunk() — non-contiguous views from narrow() hit the same path. ComfyUI’s tiled_scale_multidim uses narrow() to slice tiles, which lands exactly on this bug.
Affected versions: PyTorch 2.9.0 / 2.9.1 / 2.10.0. CUDA / CPU don’t reproduce it. MPS-only.
The related PR #169935 is up but it’s a narrow workaround that only forces contiguous() on M5 chips. M1–M4 users probably won’t see an upstream fix from that PR, so plan on keeping the local contiguous() patch.
How to confirm the bug quickly
Shortest path to convincing yourself the issue isn’t input-dependent:
- Add a
PreviewImagenode on theImageUpscaleWithModeloutput - If the preview is “broken-TV static,” the upscale node itself is broken, not anything upstream
- Then check whether
comfy/utils.pystill has.contiguous()applied
You don’t even need to use the GUI — you can splice a PreviewImage into the workflow JSON inside the PNG metadata and POST it to /prompt directly to verify.
Detecting recurrence after future updates
Hitting this every time ComfyUI updates is a waste, so a one-line grep wrapped in a shell function (e.g. in ~/.zshrc) saves time.
comfy_check_patch() {
if grep -q 'function(s_in.contiguous())' ~/ComfyUI/comfy/utils.py; then
echo "[ok] contiguous patch is present"
else
echo "[warn] contiguous patch is MISSING — re-apply before running on MPS"
return 1
fi
}
If you have a ComfyUI launcher script, prepend comfy_check_patch || return 1 to fail fast instead of finding out after a broken render.
After re-patching
Before/after for the record. With the patch reapplied, both raw ([42]) and final ([54]) outputs come back to normal:
| Node [42] (right after 4x-UltraSharp) | Final output [54] |
|---|---|
![]() | ![]() |



