From 47aa9a2c93fd95b2a90170117f1ea264c50cf792 Mon Sep 17 00:00:00 2001 From: CalamitousFelicitousness Date: Wed, 10 Jun 2026 01:27:38 +0100 Subject: [PATCH] fix(samplers): report validation failures without backtrace Sampler capability gates raised plain ValueError when schedulers_fallback is disabled, so the API middleware and the gradio call wrapper printed a full backtrace for an expected outcome. Add errors.ValidationError, raise it from the gates, and report it message-only in errors.display; the UI error box and the API error response already carry the message. --- modules/errors.py | 7 +++++++ modules/sd_samplers.py | 8 ++++---- modules/sd_samplers_diffusers.py | 10 +++++----- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/modules/errors.py b/modules/errors.py index 32bf3f9dd..5faf6f9b7 100644 --- a/modules/errors.py +++ b/modules/errors.py @@ -10,6 +10,10 @@ install_traceback() already_displayed = {} +class ValidationError(ValueError): + """Expected validation failure: display() reports the message without a traceback.""" + + def install(suppress=None): if suppress is None: suppress = [] @@ -23,6 +27,9 @@ def display(e: Exception, task: str, suppress=None): suppress = [] if isinstance(e, ErrorLimiterAbort): return + if isinstance(e, ValidationError): + log.error(f"{task or 'error'}: {e}") + return log.error(f"{task or 'error'}: {type(e).__name__}") """ trace = traceback.format_exc() diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index ef46719ba..9fbdf0a5a 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -1,6 +1,6 @@ import os import copy -from modules import shared +from modules import shared, errors from modules.logger import log @@ -108,7 +108,7 @@ def create_sampler(name, model, scheduler_overrides=None): if config is None or config.constructor is None: if debug or not shared.opts.schedulers_fallback: - raise ValueError(f'Sampler: name="{name}" unknown') + raise errors.ValidationError(f'Sampler: name="{name}" unknown') return restore_default(model, name) from modules import sd_samplers_diffusers @@ -129,13 +129,13 @@ def create_sampler(name, model, scheduler_overrides=None): elif (model is not None) and (is_flow and not requires_flow): log.error(f'Sampler: "{sampler.name}" cls={sampler.sampler.__class__.__name__} pipe={model.__class__.__name__} type={pred_type} model requires sampler with discrete prediction') if debug or not shared.opts.schedulers_fallback: - raise ValueError(f'Sampler: name="{sampler.name}" cls={sampler.sampler.__class__.__name__} type={pred_type} model requires sampler with discrete prediction') + raise errors.ValidationError(f'Sampler: name="{sampler.name}" cls={sampler.sampler.__class__.__name__} type={pred_type} model requires sampler with discrete prediction') else: return restore_default(model, name) elif (model is not None) and (not is_flow and requires_flow): log.error(f'Sampler: "{sampler.name}" cls={sampler.sampler.__class__.__name__} pipe={model.__class__.__name__} type={pred_type} model requires sampler with flow prediction') if debug or not shared.opts.schedulers_fallback: - raise ValueError(f'Sampler: name="{sampler.name}" cls={sampler.sampler.__class__.__name__} type={pred_type} model requires sampler with flow prediction') + raise errors.ValidationError(f'Sampler: name="{sampler.name}" cls={sampler.sampler.__class__.__name__} type={pred_type} model requires sampler with flow prediction') else: return restore_default(model, name) diff --git a/modules/sd_samplers_diffusers.py b/modules/sd_samplers_diffusers.py index e69e426a7..043eda07a 100644 --- a/modules/sd_samplers_diffusers.py +++ b/modules/sd_samplers_diffusers.py @@ -450,7 +450,7 @@ class DiffusionSampler: sigma_applied = True if not sigma_applied: if debug or not shared.opts.schedulers_fallback: - raise ValueError(f'Sampler: name="{name}" does not support sigma="{sched_sigma}"') + raise errors.ValidationError(f'Sampler: name="{name}" does not support sigma="{sched_sigma}"') else: log.warning(f'Sampler: name="{name}" does not support sigma="{sched_sigma}", using default schedule') else: @@ -520,7 +520,7 @@ class DiffusionSampler: if debug: errors.display(e, 'Samplers') if debug or not shared.opts.schedulers_fallback: - raise + raise errors.ValidationError(f'Sampler: name="{name}" {e}') from e self.sampler = None return @@ -529,7 +529,7 @@ class DiffusionSampler: cls_source = inspect.getsource(constructor) if '"flow_prediction"' not in cls_source and "'flow_prediction'" not in cls_source: if debug or not shared.opts.schedulers_fallback: - raise ValueError(f'Sampler: name="{name}" does not appear to support flow_prediction') + raise errors.ValidationError(f'Sampler: name="{name}" does not appear to support flow_prediction') else: log.warning(f'Sampler: name="{name}" does not support flow_prediction') self.sampler = None @@ -549,7 +549,7 @@ class DiffusionSampler: default_accept_sigmas = (model is not None) and hasattr(model.default_scheduler, 'set_timesteps') and "sigmas" in set(inspect.signature(model.default_scheduler.set_timesteps).parameters.keys()) if default_accept_sigmas and not accept_sigmas: if debug or not shared.opts.schedulers_fallback: - raise ValueError(f'Sampler: name="{name}" does not accept sigmas') + raise errors.ValidationError(f'Sampler: name="{name}" does not accept sigmas') else: log.warning(f'Sampler: name="{name}" does not accept sigmas') self.sampler = None @@ -559,7 +559,7 @@ class DiffusionSampler: if default_accept_scale_noise and not accept_scale_noise: log.warning(f'Sampler: name="{name}" does not implement scale noise') if debug or not shared.opts.schedulers_fallback: - raise ValueError(f'Sampler: name="{name}" does not implement scale noise') + raise errors.ValidationError(f'Sampler: name="{name}" does not implement scale noise') else: log.warning(f'Sampler: name="{name}" does not implement scale noise') self.sampler = None