invoke-ai/InvokeAI · error · ValueError

denoising_start must be less than denoising_end.

Error message

denoising_start must be less than denoising_end.

What it means

`_validate_inputs` enforces that the denoising window is a valid interval: denoising_start must be strictly less than denoising_end. Equal or inverted values define an empty or reversed range and are rejected before scheduling.

Source

Thrown at invokeai/app/invocations/krea2_denoise.py:231

                )
            return self.cfg_scale
        raise ValueError(f"Invalid CFG scale type: {type(self.cfg_scale)}")

    @staticmethod
    def _should_apply_cfg_for_step(cfg_scale: float, *, has_negative_conditioning: bool) -> bool:
        return has_negative_conditioning and cfg_scale > 1.0

    @staticmethod
    def _validate_effective_schedule(*, start_idx: int, end_idx: int) -> None:
        if end_idx <= start_idx:
            raise ValueError(
                "The requested denoising range does not contain any effective denoising steps at the configured "
                "step count. Increase denoising_end, decrease denoising_start, or increase steps."
            )

    def _validate_inputs(self) -> None:
        if self.denoising_start >= self.denoising_end:
            raise ValueError("denoising_start must be less than denoising_end.")
        if self.denoise_mask is not None and self.latents is None:
            raise ValueError("Initial latents are required when a denoise mask is provided.")

    def _is_distilled(self, context: InvocationContext) -> bool:
        """Whether the transformer is the distilled Turbo checkpoint (fixed mu) vs. Raw (dynamic mu).

        Prefer the classified variant (works for diffusers, single-file and GGUF alike); fall back to
        the pipeline-level ``is_distilled`` flag in model_index.json, then default to distilled.

        A failed config lookup is a real error and is allowed to propagate — silently defaulting to the
        Turbo shift would apply the wrong sampling schedule to a Raw model.
        """
        from invokeai.backend.model_manager.taxonomy import Krea2VariantType

        config = context.models.get_config(self.transformer.transformer)
        variant = getattr(config, "variant", None)
        if variant is not None:
            return variant != Krea2VariantType.Base

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Set denoising_end strictly greater than denoising_start (e.g. start=0.5, end=1.0).
  2. Add a caller-side clamp: if start >= end, widen end or reset to defaults (0.0 / 1.0).
  3. Fix swapped variables in scripts that compute the range dynamically.

Example fix

// before
denoising_start=0.9; denoising_end=0.5
// after
denoising_start, denoising_end = min(0.5, 0.9), max(0.5, 0.9)  # 0.5, 0.9
Defensive patterns

Strategy: validation

Validate before calling

if denoising_start >= denoising_end:
    raise ValueError(f"denoising_start ({denoising_start}) must be < denoising_end ({denoising_end})")

Type guard

def is_valid_denoise_window(start: float, end: float) -> bool:
    return 0.0 <= start < end <= 1.0

Try / catch

try:
    out = invoke_krea2_denoise(denoising_start=start, denoising_end=end)
except ValueError as e:
    if "must be less than denoising_end" in str(e):
        start, end = sorted((start, end))
        out = invoke_krea2_denoise(denoising_start=start, denoising_end=end)
    else:
        raise

Prevention

When it happens

Trigger: Setting denoising_start >= denoising_end on the krea2_denoise invocation, e.g. start=0.8, end=0.8, or swapped values like start=0.9, end=0.5.

Common situations: UI slider ranges that can collapse to equal values; programmatically generated graphs where start/end variables are swapped; refiner setups configured with a zero-width window.

Related errors


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