Comfy-Org/ComfyUI · error · ValueError
TripoSplatPreprocessImage: mask is empty (no foreground pixe
Error message
TripoSplatPreprocessImage: mask is empty (no foreground pixels).
What it means
TripoSplatPreprocessImage crops an RGBA image around its alpha foreground. After optional erosion (a min-filter over the alpha channel) it finds nonzero alpha pixels; if none remain, the mask is empty and there is nothing to crop, so it raises. The erosion step can shrink a thin or weak alpha matte to nothing.
Source
Thrown at comfy_extras/nodes_triposplat.py:44
# Match original preprocessing:
# resize min side to `size` -> erode alpha -> alpha bbox -> 1.2x square crop -> resize -> composite on black.
rgb = image[..., :3].clamp(0, 1).movedim(-1, 0) # (3, H, W)
alpha = mask.clamp(0, 1)[None] # (1, H, W)
rgba = torch.cat([rgb, alpha], 0)[None] # (1, 4, H, W)
h, w = rgba.shape[-2:]
s = size / min(w, h)
rgba = comfy.utils.common_upscale(rgba, max(1, round(w * s)), max(1, round(h * s)), "lanczos", "disabled").clamp(0, 1)
a = rgba[:, 3:4]
if erode_radius > 0:
# min filter over a (2r+1) window == morphological erosion of the alpha matte.
a = -F.max_pool2d(-a, 2 * erode_radius + 1, stride=1, padding=erode_radius)
rgba = torch.cat([rgba[:, :3], a], 1)
ys, xs = torch.nonzero(a[0, 0] > 0, as_tuple=True)
if xs.numel() == 0:
raise ValueError("TripoSplatPreprocessImage: mask is empty (no foreground pixels).")
x0, x1 = int(xs.min()), int(xs.max())
y0, y1 = int(ys.min()), int(ys.max())
cx, cy = (x0 + x1) / 2, (y0 + y1) / 2
half = max(x1 - x0, y1 - y0) / 2 * 1.2
left, upper, right, lower = int(cx - half), int(cy - half), int(cx + half), int(cy + half)
H, W = rgba.shape[-2:]
crop = rgba.new_zeros((1, 4, lower - upper, right - left)) # out-of-bounds stays 0, matching PIL.crop
sx0, sy0, sx1, sy1 = max(left, 0), max(upper, 0), min(right, W), min(lower, H)
if sx1 > sx0 and sy1 > sy0:
crop[:, :, sy0 - upper:sy1 - upper, sx0 - left:sx1 - left] = rgba[:, :, sy0:sy1, sx0:sx1]
crop = comfy.utils.common_upscale(crop, size, size, "lanczos", "disabled").clamp(0, 1)
out = (crop[:, :3] * crop[:, 3:4])[0].movedim(0, -1) # composite over black == rgb * alpha
return out.unsqueeze(0) # (1, 1024, 1024, 3)
class TripoSplatPreprocessImage(IO.ComfyNode):View on GitHub (pinned to 1c6d8d45b3)
Solutions
- Verify the input image actually has foreground alpha > 0 (inspect the alpha channel statistics)
- Reduce erode_radius so erosion does not consume the whole matte
- Re-export the image with a correct alpha channel from the background-removal tool
Example fix
# before: erosion wipes out a thin matte pre = TripoSplatPreprocessImage.execute(rgba, size=512, erode_radius=15) # after: smaller erosion radius pre = TripoSplatPreprocessImage.execute(rgba, size=512, erode_radius=2)
Defensive patterns
Strategy: validation
Validate before calling
alpha = rgba[:, 3:4]
# simulate the erosion the node applies
eroded = -torch.nn.functional.max_pool2d(-alpha, 2 * erode_radius + 1, 1, erode_radius)
if (eroded[0, 0] > 0).sum() == 0:
erode_radius = 0 # or reject the image Type guard
def has_foreground(rgba: torch.Tensor) -> bool:
return bool((rgba[:, 3] > 0).any()) Prevention
- Check alpha statistics (min/max/nonzero count) before preprocessing
- Keep erode_radius small relative to the thinnest foreground feature
When it happens
Trigger: Input RGBA image whose alpha channel is all zeros, or alpha that becomes all zeros after erode_radius erosion — e.g. a faint silhouette with alpha values of 1-2 out of 255, or a fine hair/thin-object matte eroded by a radius larger than the feature width.
Common situations: Background-removed images saved without alpha (fully transparent); PNG with black alpha channel; overly large erode_radius for delicate mattes; images where segmentation produced an empty mask.
Related errors
AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14).
Data as JSON: /api/errors/3f17c286e209716f.
Report an issue: GitHub.