unslothai/unsloth · error · ValueError

duplicate LoRA id '{spec.id}'; list each adapter at most onc

Error message

duplicate LoRA id '{spec.id}'; list each adapter at most once

What it means

Raised by the loras field_validator on the quantize/build request when the same LoRA id appears more than once. _resolve_lora_set suffixes colliding adapter names, so a repeated id resolves the SAME adapter twice and set_adapters stacks both copies past the per-adapter weight bound. On this path the mistake is baked into the quantized build before compilation, so it rides every generated image until a reload.

Source

Thrown at studio/backend/models/inference.py:2862

    @field_validator("attention_backend", mode = "before")
    @classmethod
    def _normalize_attention_backend(cls, value):
        # The dispatcher accepts case/whitespace variants, but the Literal above is validated before any normaliser runs, so fold it here.
        return value.strip().lower() if isinstance(value, str) else value

    @field_validator("loras")
    @classmethod
    def _unique_lora_ids(cls, value: Optional[list["LoraSpec"]]) -> Optional[list["LoraSpec"]]:
        # Same guard DiffusionGenerateRequest carries, and it matters more here: _resolve_lora_set
        # suffixes colliding adapter names, so a repeated id resolves the SAME adapter twice and
        # set_adapters stacks both copies past the per-adapter weight bound. On the generation path
        # that is one bad image; on this path the adapters are baked into the quantized build
        # before compilation, so the unintended combination rides every image until a reload.
        if value:
            seen: set[str] = set()
            for spec in value:
                if spec.id in seen:
                    raise ValueError(
                        f"duplicate LoRA id '{spec.id}'; list each adapter at most once"
                    )
                seen.add(spec.id)
        return value


class LoraSpec(BaseModel):
    """One LoRA adapter to apply for a generation, referenced by its discovery id.

    The id is resolved against the backend's own LoRA catalog + local scan (see
    core/inference/diffusion_lora.py); the client never supplies a raw filesystem
    path, so an arbitrary file can't be loaded. Weight 0 disables the adapter.
    """

    id: str = Field(
        ..., min_length = 1, max_length = 512, description = "LoRA discovery id (repo id or local stem)"
    )
    weight: float = Field(

View on GitHub (pinned to 203007d190)

Solutions

  1. Deduplicate by id client-side before submitting (keep the intended weight for each).
  2. To strengthen an adapter, raise its weight (0 disables; per-adapter bound applies) instead of listing it twice.
  3. If merging preset + user LoRA lists, make the merge key the adapter id.

Example fix

# before
loras = user_loras + preset_loras  # may contain 'sketch' twice

# after
by_id = {s['id']: s for s in user_loras + preset_loras}
loras = list(by_id.values())
Defensive patterns

Strategy: validation

Validate before calling

def dedupe_loras(loras: list[dict] | None) -> list[dict] | None:
    if not loras:
        return loras
    return list({spec['id']: spec for spec in loras}.values())

Prevention

When it happens

Trigger: POSTing a quantize request with loras: [{"id": "sketch", "weight": 0.5}, {"id": "sketch", "weight": 0.3}] — an attempt to double-apply or layer the same adapter.

Common situations: Prompt-driven pipelines that merge multiple LoRA lists (user + preset) without deduping; UI state where re-adding an adapter appends instead of replaces; users trying to strengthen an effect by repeating the adapter rather than raising weight.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/bbf3893e6ab15039. Report an issue: GitHub.