{"record":{"id":"c217b11df7822a40","repo":"unslothai/unsloth","slug":"resolved-family-trains-at-a-resolution-that-is","errorCode":null,"errorMessage":"'{resolved_family}' trains at a resolution that is a multiple of {_VIDEO_RESOLUTION_MULTIPLE} (its VAE compresses space by that factor); got {self.resolution}.","messagePattern":"'(.+?)' trains at a resolution that is a multiple of (.+?) \\(its VAE compresses space by that factor\\); got (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/training/diffusion_train_common.py","lineNumber":1029,"sourceCode":"        if self.train_batch_size < 1:\n            raise ValueError(\"train_batch_size must be >= 1\")\n        if self.gradient_accumulation_steps < 1:\n            raise ValueError(\"gradient_accumulation_steps must be >= 1\")\n        if self.lora_rank < 1:\n            raise ValueError(\"lora_rank must be >= 1\")\n        if self.lora_alpha is not None and self.lora_alpha < 1:\n            raise ValueError(\n                \"lora_alpha must be >= 1 (a zero/negative alpha scales the adapter to nothing)\"\n            )\n        if self.resolution < 64 or self.resolution % 8 != 0:\n            raise ValueError(\"resolution must be a multiple of 8 and >= 64\")\n        # A video family's VAE compresses space by 32, so an off-grid resolution changes the\n        # latent geometry silently. Refuse it here, before the GPU models are evicted.\n        if (\n            resolved_family in TRAINABLE_VIDEO_FAMILIES\n            and self.resolution % _VIDEO_RESOLUTION_MULTIPLE != 0\n        ):\n            raise ValueError(\n                f\"'{resolved_family}' trains at a resolution that is a multiple of \"\n                f\"{_VIDEO_RESOLUTION_MULTIPLE} (its VAE compresses space by that factor); \"\n                f\"got {self.resolution}.\"\n            )\n        if self.mixed_precision not in (\"bf16\", \"fp16\", \"no\"):\n            raise ValueError(\"mixed_precision must be one of bf16 / fp16 / no\")\n        # torch.manual_seed unpacks int64/uint64, so anything wider raises inside the trainer, after eviction. Catch it here.\n        if not -(2**63) <= int(self.seed) <= 2**64 - 1:\n            raise ValueError(\"seed must fit in torch's 64-bit range\")\n        # Refuse fp16 for a bf16-only DiT family up front, before evicting resident models.\n        if self.mixed_precision == \"fp16\" and resolved_family in _FORCE_BF16_FAMILIES:\n            raise ValueError(\n                f\"'{resolved_family}' LoRA training requires bf16: fp16 overflows its fp32 \"\n                f\"RoPE / embedder internals. Set mixed precision to bf16.\"\n            )\n        if str(self.lr_scheduler) not in _LR_SCHEDULERS:\n            raise ValueError(\n                f\"lr_scheduler must be one of {', '.join(sorted(_LR_SCHEDULERS))}; \"","sourceCodeStart":1011,"sourceCodeEnd":1047,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/training/diffusion_train_common.py#L1011-L1047","documentation":"Raised when a video-family model's training resolution is not a multiple of _VIDEO_RESOLUTION_MULTIPLE (32). Video VAEs compress spatial dimensions by 32 rather than 8, so an off-grid resolution silently changes the latent geometry and produces corrupted/incorrect crops. The validator refuses it before the run starts, while eviction of resident GPU models is still cheap to avoid.","triggerScenarios":"Training a video family (e.g. one of TRAINABLE_VIDEO_FAMILIES such as an Hunyuan/SVD-style DiT) with a resolution that passes the general % 8 check but not % 32 — e.g. 520, 640 is fine, 512+8=520 is not. Configs ported from image (x8) training to video training hit this.","commonSituations":"Reusing an image-model resolution bucket (e.g. 896 or 712) for a video model; dataset-native resolutions that are multiples of 8 but not 32; assuming the % 8 rule is the only constraint.","solutions":["Set the resolution to a multiple of 32 that is >= 64 (e.g. 512, 576, 640, 768).","Round up: resolution = ((desired + 31) // 32) * 32.","When porting a config from image to video training, re-check every resolution field against the 32 grid."],"exampleFix":"# before (image-style bucket, 8-multiple but not 32)\nconfig = TrainConfig(resolution=712, ...)\n\n# after\nconfig = TrainConfig(resolution=736, ...)","handlingStrategy":"validation","validationCode":"VIDEO_MULTIPLE = 32\n\ndef check_video_resolution(resolution, family) -> int:\n    r = int(resolution)\n    if r < 64 or r % 8 != 0:\n        raise ValueError(f\"resolution must be a multiple of 8 and >= 64, got {r}\")\n    if family in TRAINABLE_VIDEO_FAMILIES and r % VIDEO_MULTIPLE != 0:\n        raise ValueError(f\"video family {family} needs resolution % {VIDEO_MULTIPLE} == 0, got {r}\")\n    return r\n\ndef snap_video_resolution(r) -> int:\n    return max(64, ((int(r) + VIDEO_MULTIPLE - 1) // VIDEO_MULTIPLE) * VIDEO_MULTIPLE)","typeGuard":"def is_valid_video_resolution(v, family) -> bool:\n    try:\n        r = int(v)\n    except (TypeError, ValueError):\n        return False\n    if r < 64 or r % 8 != 0:\n        return False\n    return family not in TRAINABLE_VIDEO_FAMILIES or r % 32 == 0","tryCatchPattern":"try:\n    session.submit_training(config)\nexcept ValueError as e:\n    if \"multiple of\" in str(e) and \"VAE compresses\" in str(e):\n        config.resolution = snap_video_resolution(config.resolution)\n        session.submit_training(config)\n    else:\n        raise","preventionTips":["Key your resolution snapping on family: 8-grid for image families, 32-grid for video families.","Never reuse an image-model bucket list for video training without re-validating.","Centralize the family -> resolution-multiple mapping in one helper so both validation and UI use it."],"tags":["training","video","resolution","validation","diffusion"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}