Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions nodes_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2753,6 +2753,28 @@ def INPUT_TYPES(s):
CATEGORY = "WanVideoWrapper"
EXPERIMENTAL = True

@classmethod
def VALIDATE_INPUTS(cls, steps, start_step, end_step, **kwargs):
# Run at prompt-queue time, before any node executes — this prevents
# an upstream sampler from loading the model and burning GPU time on
# work that a downstream sampler with an empty timestep slice will
# then crash on (UnboundLocalError: 'callback_latent' / 'noise_pred').
if start_step >= steps:
return (
f"start_step ({start_step}) must be < steps ({steps}); "
f"the requested range would produce an empty timestep slice "
f"and the sampler would crash mid-graph."
)
if end_step != -1:
if end_step > steps:
return f"end_step ({end_step}) must be <= steps ({steps})."
if end_step <= start_step:
return (
f"end_step ({end_step}) must be > start_step ({start_step}); "
f"the requested range would produce an empty timestep slice."
)
return True

def process(self, scheduler, steps, start_step, end_step, shift, unique_id, sigmas=None, enhance_hf=False):
sample_scheduler, timesteps, start_idx, end_idx = get_scheduler(
scheduler, steps, start_step, end_step, shift, device, sigmas=sigmas, log_timesteps=True, enhance_hf=enhance_hf)
Expand Down
16 changes: 15 additions & 1 deletion wanvideo/schedulers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,22 @@ def get_scheduler(scheduler, steps, start_step, end_step, shift, device, transfo
sample_scheduler.sigmas = torch.cat([timesteps / 1000, torch.zeros(1, device=timesteps.device)])

steps = len(timesteps)
# Reject ranges that produce an empty timestep slice — otherwise the
# sampler's main loop never executes and downstream code (e.g. callbacks
# referenced after the loop) crashes with a confusing UnboundLocalError.
if isinstance(start_step, int) and start_step >= steps:
raise ValueError(
f"start_step ({start_step}) must be < steps ({steps}); "
f"the requested range would produce an empty timestep slice"
)
if isinstance(end_step, int) and end_step != -1 and end_step > steps:
raise ValueError(
f"end_step ({end_step}) must be <= steps ({steps})"
)
if (isinstance(start_step, int) and end_step != -1 and start_step >= end_step) or (not isinstance(start_step, int) and start_step != -1 and end_step >= start_step):
raise ValueError("start_step must be less than end_step")
raise ValueError(
f"start_step ({start_step}) must be less than end_step ({end_step})"
)

# Determine start and end indices for slicing
start_idx = 0
Expand Down