hiyouga/LlamaFactory · error · ValueError

Unknown params for {cls.__name__}.{params_cls.__name__}: {so

Error message

Unknown params for {cls.__name__}.{params_cls.__name__}: {sorted(unknown)}. Expected: {sorted(known)}

What it means

LlamaFactory v1's BasePlugin.parse_params (src/llamafactory/v1/utils/plugin.py:90) strictly validates the config dict for a plugin against its params dataclass (e.g. LoraParams, BnbParams, FSDP2Params, DeepSpeedParams). Any key in the config that is not a field of that dataclass raises this ValueError, listing both the unknown keys and the accepted ones. This is a fail-fast guard against typos and stale config keys in nested YAML/JSON config sections such as lora_config, quant_config, or dist_config, so misconfiguration surfaces at parse time instead of silently being ignored.

Source

Thrown at src/llamafactory/v1/utils/plugin.py:90

    def parse_params(cls, config: Any, params_cls: type[ParamsT]) -> ParamsT:
        """Strictly convert config to the params dataclass used by one plugin entrypoint."""
        if not is_dataclass(params_cls):
            raise TypeError(f"{cls.__name__} params must be a dataclass type, got {params_cls!r}.")
        if isinstance(config, params_cls):
            return config
        if config is None:
            values = {}
        elif isinstance(config, dict):
            values = dict(config)
        else:
            raise TypeError(
                f"{cls.__name__} config must be a mapping or {params_cls.__name__}, got {type(config).__name__}."
            )

        known = {item.name for item in fields(params_cls)}
        unknown = set(values) - known
        if unknown:
            raise ValueError(
                f"Unknown params for {cls.__name__}.{params_cls.__name__}: {sorted(unknown)}. "
                f"Expected: {sorted(known)}"
            )

        return params_cls(**values)

    def _resolve(self) -> Any:
        cls = type(self)
        if self.name is None:
            raise ValueError(f"{cls.__name__} must be constructed with a name.")
        if self.name not in cls._registry:
            raise ValueError(f"Plugin {self.name!r} is not registered under {cls.__name__}.")
        return cls._registry[self.name]

    def __call__(self, *args, **kwargs) -> Any:
        return self._resolve()(*args, **kwargs)

    def __getattr__(self, attr: str) -> Any:

View on GitHub (pinned to f28afaf635)

Solutions

  1. Read the error message: it prints the exact sorted unknown keys and the sorted accepted keys for the plugin/dataclass pair — rename or remove the unknown keys in your config accordingly (e.g. lora_config: {rank: 8, alpha: 16} not {lora_rank: 8}).
  2. Inspect the params dataclass fields directly: python -c "from dataclasses import fields; from llamafactory.v1.plugins.model_plugins.peft import LoraParams; print([f.name for f in fields(LoraParams)])" and align your YAML keys to that list.
  3. If the key genuinely should be supported, check the version's dataclass definition in src/llamafactory/v1/plugins/ for renames (v0 names like lora_* may map to v1 names without the prefix) and update the config to the current names.
  4. If you are authoring a custom plugin, add the missing field (with default) to your params dataclass before calling parse_params, or filter the incoming dict to known keys when v0 compatibility is intended.

Example fix

# before (YAML) — lora_rank/lora_alpha are not LoraParams fields
finetuning_args:
  lora_config:
    lora_rank: 8
    lora_alpha: 16

# after — keys match the LoraParams dataclass fields
finetuning_args:
  lora_config:
    rank: 8
    alpha: 16
Defensive patterns

Strategy: validation

Validate before calling

from dataclasses import fields


def validate_plugin_params(plugin_cls, params_cls, config: dict) -> list[str]:
    """Return the list of unknown keys; empty list means parse_params will succeed."""
    if config is None or isinstance(config, params_cls):
        return []
    if not isinstance(config, dict):
        raise TypeError(f"config must be a mapping, got {type(config).__name__}")
    known = {f.name for f in fields(params_cls)}
    return sorted(set(config) - known)


# usage before calling e.g. PeftPlugin("lora").entrypoint(lora_config)
bad = validate_plugin_params(PeftPlugin, LoraParams, yaml_lora_config)
if bad:
    raise SystemExit(f"Fix config keys {bad}; allowed: {[f.name for f in fields(LoraParams)]}")

Type guard

from dataclasses import fields
from typing import TypeVar

ParamsT = TypeVar("ParamsT")


def has_only_known_keys(config: dict, params_cls: type[ParamsT]) -> bool:
    """True when every key of config is a field of params_cls (parse_params will pass)."""
    return set(config) <= {f.name for f in fields(params_cls)}

Try / catch

try:
    params = PeftPlugin.parse_params(raw_config, LoraParams)
except ValueError as e:
    if "Unknown params" in str(e):
        # e lists sorted unknown and expected keys; surface them to the user
        raise SystemExit(f"Invalid plugin config: {e}") from None
    raise

Prevention

When it happens

Trigger: Passing a dict with a key that is not a field of the target params dataclass: PeftPlugin.parse_params(peft_config, LoraParams) with lora_config: {lora_rank: 8} when the field is named rank; QuantizationPlugin.parse_params(quant_config, BnbParams) with quant_config containing compute_dtype instead of bnb_4bit_compute_dtype; DistributedPlugin.parse_params(dist_config, FSDP2Params) with a DeepSpeed-style key like deepspeed_config. Triggered whenever USE_V1=1 and the YAML config's nested *_config section contains renamed, misspelled, or v0-style keys.

Common situations: Typos in nested YAML config keys (lora_rank vs rank, lora_alpha vs alpha); reusing a v0-era YAML where nested option names differ from the v1 params dataclass; upgrading LlamaFactory when a params dataclass renamed or removed fields; copying a dist_config block written for deepspeed into an fsdp2 run (or vice versa); passing an entire top-level training args dict where only the plugin sub-section is expected.

Related errors


AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14). Data as JSON: /api/errors/c92f9c7ff7aee94f. Report an issue: GitHub.