{"record":{"id":"8564d0d9f055d740","repo":"unslothai/unsloth","slug":"refusing-to-train-from-untrusted-base-model-base","errorCode":null,"errorMessage":"Refusing to train from untrusted base model '{base_model}'. Use a local path or a trusted repo (an unsloth/* repo or an official base).","messagePattern":"Refusing to train from untrusted base model '(.+?)'\\. Use a local path or a trusted repo \\(an unsloth/\\* repo or an official base\\)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/training/diffusion_train_common.py","lineNumber":1804,"sourceCode":"\n\ndef _assert_trusted_base_model(base_model: str, *, allow_modular: bool = False) -> None:\n    \"\"\"Gate the training base model the same way the inference backend gates non-GGUF loads:\n    a local path or a trusted repo (``unsloth/*`` or an allowlisted official base). This runs\n    BEFORE ``from_pretrained`` so an untrusted remote repo (which could ship pickle weights)\n    is never fetched or deserialised.\n\n    ``allow_modular`` is for a trainer whose loader is ``ModularPipeline.from_pretrained``: a\n    local MiniMax-H3 pipeline carries ``modular_model_index.json`` and no ``model_index.json``,\n    so the conventional shape check rejected the one local layout that family HAS.\"\"\"\n    from core.inference.diffusion import _assert_local_base_is_pipeline, _is_trusted_diffusion_repo\n\n    trusted = (\n        _is_trusted_diffusion_repo(base_model)\n        or str(base_model or \"\").strip().lower() in _TRAIN_EXTRA_TRUSTED_REPOS\n    )\n    if not trusted:\n        raise ValueError(\n            f\"Refusing to train from untrusted base model '{base_model}'. Use a local path or \"\n            f\"a trusted repo (an unsloth/* repo or an official base).\"\n        )\n    # An existing LOCAL base is loaded as a full pipeline, which needs an index; reject a non-pipeline local dir before /diffusion/start frees the GPU models.\n    _assert_local_base_is_pipeline(base_model, allow_modular = allow_modular)\n\n\n# ── resume checkpoints ────────────────────────────────────────────────────────\n# One writer and one reader for BOTH trainers, so an SDXL and a DiT run resume from the same\n# bundle shape. The family-specific part (the deployable adapter export) stays in the trainers.\ndef trainable_state_dict(model: Any) -> dict[str, Any]:\n    \"\"\"The trainable (LoRA) parameters of ``model``, keyed by parameter name.\n\n    Deliberately NOT the peft/diffusers export format: this is the checkpoint's private\n    copy of exactly the tensors the optimizer holds moments for, so restoring it and the\n    optimizer state together reproduces the run bit-for-bit. Parameter names are stable\n    across a re-attach and across regional torch.compile (which compiles submodules in\n    place without renaming), which is the same assumption ``LoRAEMA`` already makes.\"\"\"","sourceCodeStart":1786,"sourceCodeEnd":1822,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/training/diffusion_train_common.py#L1786-L1822","documentation":"The training base is gated exactly like the inference backend's non-GGUF loads: it must be a local path or a trusted repo (unsloth/* or an allowlisted official base, plus _TRAIN_EXTRA_TRUSTED_REPOS). The check runs BEFORE from_pretrained so an untrusted remote repo — which could ship pickle-encoded weights — is never fetched or deserialized. A local path additionally must contain a pipeline index (or modular_model_index.json when allow_modular).","triggerScenarios":"base_model set to an arbitrary Hub repo outside the trust allowlist (e.g. a random user's 'someone/my-flux-remix'), or a local directory that is not a full pipeline layout.","commonSituations":"Pointing the trainer at a community fine-tune repo with custom weights; a typo'd repo id; a local directory holding only safetensors shards without model_index.json.","solutions":["Use an official base repo for the family or an unsloth/* mirror.","Or point at a local path containing a complete diffusers pipeline (model_index.json plus component subfolders).","If the repo is genuinely trustworthy and you own the deployment, add it to the trust allowlist in code/config after reviewing what it ships — never as a blanket bypass."],"exampleFix":"# before\ncfg = DiffusionLoraConfig(base_model='randomuser/flux-finetune')\n# after\ncfg = DiffusionLoraConfig(base_model='black-forest-labs/FLUX.1-dev')\n# local path must contain model_index.json + component dirs","handlingStrategy":"validation","validationCode":"from core.inference.diffusion import _is_trusted_diffusion_repo\ndef assert_trainable_base(base_model):\n    if not (_is_trusted_diffusion_repo(base_model) or Path(base_model).expanduser().is_dir()):\n        raise ValueError(f'untrusted base model: {base_model}')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict base-model selection to the curated allowlist plus local pipeline directories.","For local bases, confirm model_index.json exists before starting; never disable the trust check."],"tags":["training","security","model-loading","trust","pickle-risk"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}