invoke-ai/InvokeAI · error · ValueError

{type(scheduler).__name__} does not accept an explicit sigma

Error message

{type(scheduler).__name__} does not accept an explicit sigma schedule, so it cannot honor denoising_start/denoising_end. Use the euler or lcm scheduler for partial denoising.

What it means

In ernie_image denoise, partial denoising (denoising_start/denoising_end) requires installing an explicit sigma schedule on the scheduler. FlowMatchHeunDiscreteScheduler.set_timesteps only accepts a step count and derives its own sigmas, so when the requested window doesn't span the full 1.0->0.0 range, the library raises ValueError instead of silently running a full denoise with the wrong schedule.

Source

Thrown at invokeai/backend/ernie_image/denoise.py:93

    if use_scheduler:
        set_timesteps_sig = inspect.signature(scheduler.set_timesteps)
        if "sigmas" in set_timesteps_sig.parameters:
            # Hand the scheduler the *whole* window -- terminal sigma included -- and then drop the
            # extra zero it unconditionally appends. Passing `timesteps[:-1]` instead would let that
            # appended zero stand in for the requested end sigma, so `denoising_end < 1.0` would
            # silently run a full denoise in fewer, coarser steps rather than stopping early.
            # Truncating (instead of patching the last sigma by hand) keeps the scheduler's own
            # `shift` applied to the terminal sigma, which manual math here would get wrong.
            scheduler.set_timesteps(sigmas=list(timesteps), device=img.device)
            scheduler.sigmas = scheduler.sigmas[:-1]
            scheduler.timesteps = scheduler.timesteps[:-1]
        else:
            # FlowMatchHeunDiscreteScheduler.set_timesteps only takes a step count and derives its
            # own sigmas, so a partial-denoise range cannot be honored. Refuse instead of silently
            # running a full denoise with the wrong schedule.
            if not (math.isclose(timesteps[0], 1.0) and math.isclose(timesteps[-1], 0.0, abs_tol=1e-6)):
                raise ValueError(
                    f"{type(scheduler).__name__} does not accept an explicit sigma schedule, so it cannot honor "
                    "denoising_start/denoising_end. Use the euler or lcm scheduler for partial denoising."
                )
            scheduler.set_timesteps(num_inference_steps=len(timesteps) - 1, device=img.device)

        if init_latents is not None:
            # `scheduler.sigmas[0]` is the *shifted* first sigma; `timesteps[0]` is the raw one.
            # Blending at the raw value would build a sample at one sigma and then tell the first
            # model call it is at another. Equivalent to `scheduler.scale_noise`, spelled out
            # because it has to agree with the Euler math below.
            img = _blend_init_latents(init_latents, img, float(scheduler.sigmas[0]))

        # Higher-order solvers evaluate the model more than once per requested step (Heun's
        # `set_timesteps(N)` yields 2N-1 timesteps), so drive progress off the actual iteration
        # count rather than the requested step count.
        total_steps = len(scheduler.timesteps)

        pbar = tqdm(total=total_steps, desc="ERNIE-Image denoising")

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Switch the scheduler to euler or lcm, which accept explicit sigma schedules and honor partial denoising.
  2. Set denoising_start=0.0 and denoising_end=1.0 if you must keep Heun (full denoise only).
  3. Adjust graph/UI logic to restrict the Heun option to full denoise runs.

Example fix

// before
denoise(model, scheduler=FlowMatchHeunDiscreteScheduler(...), denoising_start=0.4)
// after
denoise(model, scheduler=EulerDiscreteScheduler(...), denoising_start=0.4)
Defensive patterns

Strategy: fallback

Validate before calling

is_heun = isinstance(scheduler, FlowMatchHeunDiscreteScheduler)
is_partial = denoising_start > 0.0 or denoising_end < 1.0
if is_heun and is_partial:
    scheduler = switch_to_euler(scheduler)

Type guard

def supports_explicit_sigmas(scheduler) -> bool:
    return not isinstance(scheduler, FlowMatchHeunDiscreteScheduler)

Try / catch

try:
    denoise(model, scheduler=scheduler, denoising_start=s, denoising_end=e)
except ValueError as e:
    if "explicit sigma schedule" in str(e):
        scheduler = EulerDiscreteScheduler.from_config(scheduler.config)
        return denoise(model, scheduler=scheduler, denoising_start=s, denoising_end=e)
    raise

Prevention

When it happens

Trigger: Calling denoise() with scheduler=FlowMatchHeunDiscreteScheduler and either denoising_start > 0 or denoising_end < 1.0 (i.e. timesteps slice endpoints not ~1.0 and ~0.0 within 1e-6).

Common situations: Users selecting the Heun scheduler in the UI and then setting a denoise start/end for img2img or preview; graphs that pass partial-denoise windows with Heun after switching schedulers from euler/lcm.

Related errors


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