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
- 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}).
- 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.
- 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.
- 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
- Generate YAML config sections from the params dataclass fields (python -c 'from dataclasses import fields; ...') instead of copying v0 examples with prefixed key names.
- Validate nested *_config dicts with has_only_known_keys() in a config sanity-check step before launching long training runs.
- After upgrading LlamaFactory, diff the params dataclasses your config touches (fields(...) output) against your YAML keys.
- Keep configs per plugin backend separate (a DeepSpeed dist_config block will not validate against FSDP2Params).
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
- `kt_model_max_length` must be a positive integer.
- Cannot create new adapter upon a quantized model.
- Plugin {self.name!r} is not registered under {cls.__name__}.
- Unknown mixing strategy: {data_args.mix_strategy}.
- Cannot specify `val_size` if `eval_dataset` is not None.
AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14).
Data as JSON: /api/errors/c92f9c7ff7aee94f.
Report an issue: GitHub.