unslothai/unsloth · error · ValueError

Upscale would not enlarge this image: its longest side ({max

Error message

Upscale would not enlarge this image: its longest side ({max(iw, ih)}px) already meets the {max_side}px output limit. Use a smaller source image.

What it means

In the upscale (hires-fix) workflow, the target size is computed as the input size times a factor clamped to [1.0, 4.0], then capped so the longest side does not exceed 2048px and snapped to a multiple of 16. If the source image's longest side already meets or exceeds the capped target, the 'upscale' would actually shrink or no-op, so the code refuses with this ValueError instead of returning a smaller image.

Source

Thrown at studio/backend/core/inference/diffusion.py:5388

                    pipe = self._workflow_pipe(state, state.family.inpaint_pipeline_class, workflow)
                    init_pil = decode_b64_image(init_image, mode = "RGB")
                    mask_pil = decode_b64_image(mask_image, mode = "L")
                elif init_image is not None and upscale is not None and upscale > 1.0:
                    # Upscale (hires fix): enlarge with Lanczos, then re-run img2img at low strength to add detail.
                    workflow = "upscale"
                    pipe = self._workflow_pipe(state, state.family.img2img_pipeline_class, workflow)
                    init_pil = decode_b64_image(init_image, mode = "RGB")
                    iw, ih = init_pil.size
                    # Cap the factor, then the absolute output (longest side 2048); round to a multiple of 16 (VAE downsample + patch).
                    factor = max(1.0, min(float(upscale), 4.0))
                    tw_f, th_f = iw * factor, ih * factor
                    max_side = 2048
                    fit = min(1.0, max_side / max(tw_f, th_f))
                    tw = max(16, int(round(tw_f * fit / 16.0)) * 16)
                    th = max(16, int(round(th_f * fit / 16.0)) * 16)
                    # After the cap, the target must still exceed the input (else upscale shrinks it).
                    if max(tw, th) <= max(iw, ih):
                        raise ValueError(
                            f"Upscale would not enlarge this image: its longest side "
                            f"({max(iw, ih)}px) already meets the {max_side}px output limit. "
                            f"Use a smaller source image."
                        )
                    init_pil = init_pil.resize((tw, th), Image.LANCZOS)
                    if strength is None:
                        strength = 0.35  # hires-fix default: preserve content, add detail
                elif getattr(state.family, "reference", False) and init_image is not None:
                    # FLUX.2 reference conditioning: the loaded pipe takes the reference via `image` and generates at the REQUESTED size.
                    workflow = "reference"
                    init_pil = decode_b64_image(init_image, mode = "RGB")
                    # Additional references (FLUX.2 combines a list); capped to bound VRAM.
                    ref_extra = [
                        decode_b64_image(x, mode = "RGB") for x in (reference_images or [])[:3]
                    ]
                elif init_image is not None:
                    workflow = "img2img"
                    pipe = self._workflow_pipe(state, state.family.img2img_pipeline_class, workflow)

View on GitHub (pinned to 203007d190)

Solutions

  1. Downscale the source image so its longest side is comfortably below 2048px before requesting upscale (e.g. resize to 1024-1536px longest side).
  2. Skip the upscale flag and use plain img2img at the source resolution if enlargement is not needed.
  3. Raise the max_side cap in your own fork only if you have VRAM/headroom for larger outputs — stock builds cap at 2048.

Example fix

# before
engine.generate(prompt=..., init_image=big_2048px_b64, upscale=2.0)
# after
from PIL import Image
img = decode(b64); img.thumbnail((1536, 1536))
engine.generate(prompt=..., init_image=encode_b64(img), upscale=2.0)  # 1536 -> ~3072 capped to 2048, still larger
Defensive patterns

Strategy: validation

Validate before calling

from PIL import Image
import io

MAX_SIDE = 2048

def upscale_viable(img_b64: str, upscale: float) -> bool:
    img = Image.open(io.BytesIO(decode(img_b64)))
    factor = max(1.0, min(float(upscale), 4.0))
    tw, th = img.width * factor, img.height * factor
    fit = min(1.0, MAX_SIDE / max(tw, th))
    tw = max(16, int(round(tw * fit / 16.0)) * 16)
    th = max(16, int(round(th * fit / 16.0)) * 16)
    return max(tw, th) > max(img.size)

Try / catch

try:
    out = engine.generate(prompt=p, init_image=img_b64, upscale=2.0)
except ValueError as e:
    if "would not enlarge" in str(e):
        out = engine.generate(prompt=p, init_image=downscale_b64(img_b64, longest=1536), upscale=2.0)
    else:
        raise

Prevention

When it happens

Trigger: Calling generate with init_image set, upscale > 1.0, and an input image whose max(iw, ih) is at or above 2048px (or close enough that the 16px rounding lands the target at or below the input). E.g. a 2048x1536 photo with upscale=2 would target 4096 -> capped to 2048 -> not larger than input.

Common situations: Feeding full-resolution phone photos (commonly 4000px+) into an img2img upscale endpoint; re-running upscale on an already-upscaled output that hit the 2048 cap.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/e49b3d5452491e29. Report an issue: GitHub.