invoke-ai/InvokeAI · error · ValueError

x_min ({self.x_min}) is greater than x_max ({self.x_max}).

Error message

x_min ({self.x_min}) is greater than x_max ({self.x_max}).

What it means

The segment-anything bounding-box pydantic model validates itself with a @model_validator(mode='after'): if x_min > x_max (or y_min > y_max) the box is inverted/empty and ValueError('x_min (...) is greater than x_max (...).') is raised during construction. The library enforces the inclusive-min / exclusive-max box convention so downstream cropping produces a non-empty region.

Source

Thrown at invokeai/backend/image_util/segment_anything/shared.py:16

from enum import Enum

from pydantic import BaseModel, model_validator
from pydantic.fields import Field


class BoundingBox(BaseModel):
    x_min: int = Field(..., description="The minimum x-coordinate of the bounding box (inclusive).")
    x_max: int = Field(..., description="The maximum x-coordinate of the bounding box (exclusive).")
    y_min: int = Field(..., description="The minimum y-coordinate of the bounding box (inclusive).")
    y_max: int = Field(..., description="The maximum y-coordinate of the bounding box (exclusive).")

    @model_validator(mode="after")
    def check_coords(self):
        if self.x_min > self.x_max:
            raise ValueError(f"x_min ({self.x_min}) is greater than x_max ({self.x_max}).")
        if self.y_min > self.y_max:
            raise ValueError(f"y_min ({self.y_min}) is greater than y_max ({self.y_max}).")
        return self

    def tuple(self) -> tuple[int, int, int, int]:
        """
        Returns the bounding box as a tuple suitable for use with PIL's `Image.crop()` method.
        This method returns a tuple of the form (left, upper, right, lower) == (x_min, y_min, x_max, y_max).
        """
        return (self.x_min, self.y_min, self.x_max, self.y_max)


class SAMPointLabel(Enum):
    negative = -1
    neutral = 0
    positive = 1

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Normalize the coordinates before constructing: x_min = min(x1, x2), x_max = max(x1, x2) (same for y).
  2. If the source box is (x, y, w, h), pass (x, y, x + w, y + h) and ensure w, h >= 0.
  3. Clamp or reject upstream boxes with negative width/height before they reach the model.
  4. Catch pydantic ValidationError at the API boundary to report which coordinates were inverted.

Example fix

// before
Box(x_min=x2, y_min=y1, x_max=x1, y_max=y2)  # ValueError if x1 < x2
// after
Box(x_min=min(x1, x2), y_min=min(y1, y2), x_max=max(x1, x2), y_max=max(y1, y2))
Defensive patterns

Strategy: validation

Validate before calling

def normalize_box(x1, y1, x2, y2):
    assert x1 <= x2 and y1 <= y2, f'inverted box: ({x1},{y1},{x2},{y2})'
    return x1, y1, x2, y2

Type guard

def is_valid_box(box) -> bool:
    return box.x_min <= box.x_max and box.y_min <= box.y_max

Try / catch

from pydantic import ValidationError
try:
    box = BoundingBox(x_min=x1, y_min=y1, x_max=x2, y_max=y2)
except ValidationError as e:
    logger.error('Invalid box coords (%s, %s, %s, %s): %s', x1, y1, x2, y2, e)
    box = BoundingBox(x_min=min(x1, x2), y_min=min(y1, y2), x_max=max(x1, x2), y_max=max(y1, y2))

Prevention

When it happens

Trigger: Constructing the box model (directly or via an API taking box coordinates) with x_min greater than x_max — e.g. passing corners in the wrong order (right, left), boxes computed as (x + w, x) inverted, or negative/NaN-derived widths flowing into the fields.

Common situations: Swapping the two x (or y) coordinates when converting from (x, y, w, h) or corner-pair formats; results from detection models returned with unordered corners; coordinate-space confusion (normalized 0-1 vs pixel) producing out-of-order values; negative widths from sign errors.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/5d86bd1118472528. Report an issue: GitHub.