{"record":{"id":"142e2e2e63e35f37","repo":"invoke-ai/InvokeAI","slug":"guidance-schedule-has-length-len-self-guidance-sc","errorCode":null,"errorMessage":"guidance_schedule has length {len(self.guidance_schedule)}, expected num_steps={self.num_steps}","messagePattern":"guidance_schedule has length (.+?), expected num_steps=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/ideogram4/scheduler.py","lineNumber":67,"sourceCode":"    \"\"\"Bundle of sampling hyperparameters for a named preset.\n\n    ``guidance_schedule`` is in LOOP-INDEX order: index 0 is the LAST sampling\n    step (final polish), index ``num_steps - 1`` is the FIRST sampling step.\n    ``mu`` and ``std`` are the mean and stddev of the logit-normal noise\n    schedule passed to ``get_schedule_for_resolution`` (as ``known_mean`` and\n    ``std`` respectively).\n\n    See ``ideogram4.sampler_configs.PRESETS`` for the named preset registry.\n    \"\"\"\n\n    num_steps: int\n    guidance_schedule: tuple[float, ...]\n    mu: float\n    std: float = 1.0\n\n    def __post_init__(self) -> None:\n        if len(self.guidance_schedule) != self.num_steps:\n            raise ValueError(\n                f\"guidance_schedule has length {len(self.guidance_schedule)}, expected num_steps={self.num_steps}\"\n            )\n","sourceCodeStart":49,"sourceCodeEnd":70,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/ideogram4/scheduler.py#L49-L70","documentation":"Dataclass validation in __post_init__ ensures the CFG guidance schedule has exactly one guidance value per denoising step; a mismatch would cause index errors or silently wrong guidance during sampling.","triggerScenarios":"Constructing the scheduler dataclass with a guidance_schedule tuple whose length differs from num_steps, e.g. hand-editing steps or reusing a schedule from a different run.","commonSituations":"Changing num_steps in config without regenerating the schedule, loading a schedule from a checkpoint/config of another run, off-by-one when building schedules programmatically.","solutions":["Regenerate guidance_schedule with exactly num_steps entries (e.g. scheduler.set_timesteps / build_schedule(num_steps))","Resample or interpolate the existing schedule to num_steps points","Set num_steps to len(guidance_schedule) if the schedule length is authoritative"],"exampleFix":"# before\nScheduler(num_steps=28, guidance_schedule=tuple(np.linspace(4, 7, 50)), ...)\n# after\nnum_steps = 28\nScheduler(num_steps=num_steps, guidance_schedule=tuple(np.linspace(4, 7, num_steps)), ...)","handlingStrategy":"validation","validationCode":"assert len(guidance_schedule) == num_steps, (\n    f\"schedule len {len(guidance_schedule)} != num_steps {num_steps}\"\n)\nsched = Scheduler(num_steps=num_steps, guidance_schedule=tuple(guidance_schedule), ...)","typeGuard":"def is_valid_schedule(num_steps: int, guidance_schedule) -> bool:\n    return len(guidance_schedule) == num_steps","tryCatchPattern":"try:\n    sched = Scheduler(num_steps=n, guidance_schedule=schedule, mu=mu, std=std)\nexcept ValueError as e:\n    if \"guidance_schedule has length\" in str(e):\n        schedule = tuple(np.interp(\n            np.linspace(0, 1, n),\n            np.linspace(0, 1, len(schedule)), schedule))\n        sched = Scheduler(num_steps=n, guidance_schedule=schedule, mu=mu, std=std)\n    else:\n        raise","preventionTips":["Regenerate the schedule whenever num_steps changes","Store schedule and num_steps together in one config object","Add a unit test constructing the scheduler from every config preset"],"tags":["validation","scheduler","configuration"],"backgroundTag":"invalid-configuration","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}