{"record":{"id":"131ce0be5b817ff1","repo":"unslothai/unsloth","slug":"save-steps-is-not-supported-for-resolved-family","errorCode":null,"errorMessage":"save_steps is not supported for {resolved_family}: its trainer writes no checkpoint bundle. Leave it at 0; the adapter is still saved at the end.","messagePattern":"save_steps is not supported for (.+?): its trainer writes no checkpoint bundle\\. Leave it at 0; the adapter is still saved at the end\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/training/diffusion_train_common.py","lineNumber":1084,"sourceCode":"        resume_from_checkpoint = (\n            str(self.resume_from_checkpoint).strip()\n            if self.resume_from_checkpoint is not None\n            else \"\"\n        ) or None\n        # The H3 loop does not checkpoint: it neither writes a resume bundle nor restores one.\n        # Accepting these two silently was the dangerous part -- a caller handing over a resume\n        # bundle got a FRESH optimization that then overwrote the outputs it was meant to\n        # continue, and one asking for periodic saves got none, both discovered only after an\n        # expensive run. Refuse in validation, where it costs nothing, until the loop supports it.\n        if resolved_family in CHECKPOINTLESS_FAMILIES:\n            if resume_from_checkpoint:\n                raise ValueError(\n                    f\"resume_from_checkpoint is not supported for {resolved_family}: its trainer \"\n                    f\"writes no checkpoint bundle, so there is nothing to continue from and the \"\n                    f\"run would silently start over and overwrite its output. Start a fresh run.\"\n                )\n            if save_steps:\n                raise ValueError(\n                    f\"save_steps is not supported for {resolved_family}: its trainer writes no \"\n                    f\"checkpoint bundle. Leave it at 0; the adapter is still saved at the end.\"\n                )\n        try:\n            ema_decay = float(self.ema_decay or 0.0)\n        except (TypeError, ValueError) as exc:\n            raise ValueError(f\"ema_decay must be a number, got {self.ema_decay!r}\") from exc\n        # decay = 1.0 would freeze the shadow at its init forever; the update is shadow * decay + param * (1 - decay), so valid decays live in [0, 1).\n        if not 0.0 <= ema_decay < 1.0:\n            raise ValueError(\"ema_decay must be in [0, 1); 0 disables the EMA adapter\")\n        # A blank cond_cache_dir (the Studio default when unset) means \"off\", not cwd.\n        cond_cache_dir = (\n            str(self.cond_cache_dir).strip() if self.cond_cache_dir is not None else \"\"\n        ) or None\n        compile_transformer = str(self.compile_transformer or \"auto\").strip().lower()\n        if compile_transformer not in (\"off\", \"on\", \"auto\"):\n            raise ValueError(\"compile_transformer must be one of off / on / auto\")\n        base_precision = str(self.base_precision or \"nf4\").strip().lower()","sourceCodeStart":1066,"sourceCodeEnd":1102,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/training/diffusion_train_common.py#L1066-L1102","documentation":"Raised when save_steps is non-zero for a family in CHECKPOINTLESS_FAMILIES (the H3 loop). That trainer writes no intermediate checkpoint bundle, so requesting periodic saves was previously accepted silently and the caller got no checkpoints — discovered only after an expensive run. Validation refuses it up front; note the final adapter is still saved at the end regardless.","triggerScenarios":"Submitting save_steps > 0 together with a checkpointless family. Usually a shared config template with a default save cadence (e.g. save_steps=500) applied to every family.","commonSituations":"One global training config reused across base models; UI presets that include a save cadence; migration from checkpoint-capable families where periodic saves worked.","solutions":["Leave save_steps at 0 for this family — the adapter is still saved when the run finishes.","Remove save cadence from shared config templates, or make it per-family.","If you need mid-run checkpoints, switch to a family whose trainer supports them."],"exampleFix":"# before\nconfig = TrainConfig(base_model='h3-family-model', save_steps=500)\n\n# after\nconfig = TrainConfig(base_model='h3-family-model', save_steps=0)  # final adapter still saved","handlingStrategy":"validation","validationCode":"CHECKPOINTLESS_FAMILIES = {...}\n\ndef check_save_steps_for_family(family, save_steps) -> int:\n    n = int(save_steps or 0)\n    if family in CHECKPOINTLESS_FAMILIES and n:\n        raise ValueError(f\"family {family} writes no checkpoints; save_steps must stay 0\")\n    return n","typeGuard":"def family_supports_periodic_checkpoints(family) -> bool:\n    return family not in CHECKPOINTLESS_FAMILIES","tryCatchPattern":"try:\n    session.submit_training(config)\nexcept ValueError as e:\n    if \"save_steps is not supported\" in str(e):\n        config.save_steps = 0  # final adapter is still saved; nothing else to do\n        session.submit_training(config)\n    else:\n        raise","preventionTips":["Keep save cadence out of shared config templates, or make it per-family.","Remember the final adapter is always saved — periodic steps are unnecessary for these families.","Validate checkpoint knobs against the family's capability before submission."],"tags":["training","checkpointing","validation","configuration"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}