{"record":{"id":"c92f9c7ff7aee94f","repo":"hiyouga/LlamaFactory","slug":"unknown-params-for-cls-name-params-cls-na","errorCode":null,"errorMessage":"Unknown params for {cls.__name__}.{params_cls.__name__}: {sorted(unknown)}. Expected: {sorted(known)}","messagePattern":"Unknown params for (.+?)\\.(.+?): (.+?)\\. Expected: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/llamafactory/v1/utils/plugin.py","lineNumber":90,"sourceCode":"    def parse_params(cls, config: Any, params_cls: type[ParamsT]) -> ParamsT:\n        \"\"\"Strictly convert config to the params dataclass used by one plugin entrypoint.\"\"\"\n        if not is_dataclass(params_cls):\n            raise TypeError(f\"{cls.__name__} params must be a dataclass type, got {params_cls!r}.\")\n        if isinstance(config, params_cls):\n            return config\n        if config is None:\n            values = {}\n        elif isinstance(config, dict):\n            values = dict(config)\n        else:\n            raise TypeError(\n                f\"{cls.__name__} config must be a mapping or {params_cls.__name__}, got {type(config).__name__}.\"\n            )\n\n        known = {item.name for item in fields(params_cls)}\n        unknown = set(values) - known\n        if unknown:\n            raise ValueError(\n                f\"Unknown params for {cls.__name__}.{params_cls.__name__}: {sorted(unknown)}. \"\n                f\"Expected: {sorted(known)}\"\n            )\n\n        return params_cls(**values)\n\n    def _resolve(self) -> Any:\n        cls = type(self)\n        if self.name is None:\n            raise ValueError(f\"{cls.__name__} must be constructed with a name.\")\n        if self.name not in cls._registry:\n            raise ValueError(f\"Plugin {self.name!r} is not registered under {cls.__name__}.\")\n        return cls._registry[self.name]\n\n    def __call__(self, *args, **kwargs) -> Any:\n        return self._resolve()(*args, **kwargs)\n\n    def __getattr__(self, attr: str) -> Any:","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/v1/utils/plugin.py#L72-L108","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before (YAML) — lora_rank/lora_alpha are not LoraParams fields\nfinetuning_args:\n  lora_config:\n    lora_rank: 8\n    lora_alpha: 16\n\n# after — keys match the LoraParams dataclass fields\nfinetuning_args:\n  lora_config:\n    rank: 8\n    alpha: 16","handlingStrategy":"validation","validationCode":"from dataclasses import fields\n\n\ndef validate_plugin_params(plugin_cls, params_cls, config: dict) -> list[str]:\n    \"\"\"Return the list of unknown keys; empty list means parse_params will succeed.\"\"\"\n    if config is None or isinstance(config, params_cls):\n        return []\n    if not isinstance(config, dict):\n        raise TypeError(f\"config must be a mapping, got {type(config).__name__}\")\n    known = {f.name for f in fields(params_cls)}\n    return sorted(set(config) - known)\n\n\n# usage before calling e.g. PeftPlugin(\"lora\").entrypoint(lora_config)\nbad = validate_plugin_params(PeftPlugin, LoraParams, yaml_lora_config)\nif bad:\n    raise SystemExit(f\"Fix config keys {bad}; allowed: {[f.name for f in fields(LoraParams)]}\")","typeGuard":"from dataclasses import fields\nfrom typing import TypeVar\n\nParamsT = TypeVar(\"ParamsT\")\n\n\ndef has_only_known_keys(config: dict, params_cls: type[ParamsT]) -> bool:\n    \"\"\"True when every key of config is a field of params_cls (parse_params will pass).\"\"\"\n    return set(config) <= {f.name for f in fields(params_cls)}","tryCatchPattern":"try:\n    params = PeftPlugin.parse_params(raw_config, LoraParams)\nexcept ValueError as e:\n    if \"Unknown params\" in str(e):\n        # e lists sorted unknown and expected keys; surface them to the user\n        raise SystemExit(f\"Invalid plugin config: {e}\") from None\n    raise","preventionTips":["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)."],"tags":["config","validation","llamafactory","v1-plugins","yaml"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}