unslothai/unsloth · error · ValueError

must be a multiple of 16

Error message

must be a multiple of 16

What it means

Raised by the width/height field_validator on DiffusionGenerateRequest when either dimension is not divisible by 16. Z-Image requires dimensions divisible by 16 (8x VAE downsample + 2x patch); non-multiples crash deep in the pipeline, so they are rejected up front with a clean 422.

Source

Thrown at studio/backend/models/inference.py:3072

                seen.add(spec.id)
        return value

    @field_validator("reference_images")
    @classmethod
    def _bounded_reference_items(cls, value: Optional[list[str]]) -> Optional[list[str]]:
        # Each reference is a base64 image; bound its length like init_image so several cannot buffer a multi-GB payload.
        if value is not None:
            for item in value:
                if len(item) > 32 * 1024 * 1024:
                    raise ValueError("each reference image must be at most 32 MiB (base64)")
        return value

    @field_validator("width", "height")
    @classmethod
    def _multiple_of_16(cls, value: int) -> int:
        # Z-Image requires dimensions divisible by 16 (8x VAE downsample + 2x patch); non-multiples crash deep in the pipeline.
        if value % 16 != 0:
            raise ValueError("must be a multiple of 16")
        return value

    @model_validator(mode = "after")
    def _batch_seeds_json_safe(self) -> "DiffusionGenerateRequest":
        # A batch derives seeds as seed..seed+batch_size-1, so a derived top-of-batch seed can exceed the 2**53-1 JSON-safe cap.
        if self.seed is not None and self.seed + self.batch_size - 1 > 2**53 - 1:
            raise ValueError(
                "seed + batch_size - 1 must not exceed 2**53 - 1 so every per-image seed "
                "stays JSON-safe (lower the seed or the batch_size)"
            )
        return self


class GalleryImage(BaseModel):
    """A persisted image's full generation recipe (embedded in the PNG too)."""

    id: str = Field(..., description = "Stable id (the on-disk filename stem)")
    url: str = Field(..., description = "Relative URL to fetch the PNG bytes")

View on GitHub (pinned to 203007d190)

Solutions

  1. Round dimensions to the nearest multiple of 16 client-side (see validationCode).
  2. Set slider/input step to 16 in the UI.
  3. When computing from aspect ratio, quantize both dimensions after the ratio math.

Example fix

# before
w, h = 1024, round(1024 * 1.5)  # 1536 ok, but 1365 from other ratios fails

# after
def to_multiple_of_16(v): return max(256, min(2048, round(v / 16) * 16))
w, h = to_multiple_of_16(1024), to_multiple_of_16(1024 * 1.5)
Defensive patterns

Strategy: validation

Validate before calling

def quantize_dim(v: int) -> int:
    return max(256, min(2048, round(v / 16) * 16))

Type guard

def is_valid_dimension(v: int) -> bool:
    return 256 <= v <= 2048 and v % 16 == 0

Prevention

When it happens

Trigger: POST /generate with width: 1000 or height: 1023 (the field bounds are 256..2048 but only multiples of 16 in that range are valid).

Common situations: UIs with free-form pixel inputs or sliders with step 1; deriving dimensions from aspect-ratio math (e.g. 1.5:1 of 1024 -> 1536 is fine but 1365 is not); client-side presets authored with off-by-a-few values.

Related errors


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