{"record":{"id":"4ed0bba7460fe524","repo":"hiyouga/LlamaFactory","slug":"plugin-configuration-must-have-a-name-field","errorCode":null,"errorMessage":"Plugin configuration must have a 'name' field.","messagePattern":"Plugin configuration must have a 'name' field\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/llamafactory/v1/config/arg_utils.py","lineNumber":30,"sourceCode":"# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\nimport json\nfrom enum import StrEnum, unique\n\n\nclass PluginConfig(dict):\n    \"\"\"Dictionary that allows attribute access.\"\"\"\n\n    @property\n    def name(self) -> str:\n        \"\"\"Plugin name.\"\"\"\n        if \"name\" not in self:\n            raise ValueError(\"Plugin configuration must have a 'name' field.\")\n\n        return self[\"name\"]\n\n\nPluginArgument = PluginConfig | dict | str | None\n\n\n@unique\nclass ModelClass(StrEnum):\n    \"\"\"Auto class for model config.\"\"\"\n\n    LLM = \"llm\"\n    CLS = \"cls\"\n    OTHER = \"other\"\n\n\n@unique\nclass SampleBackend(StrEnum):","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/v1/config/arg_utils.py#L12-L48","documentation":"`PluginConfig.name` is a property on the dict-with-attribute-access wrapper used for v1 plugin configs (init/peft/kernel/quant/optim etc.). Accessing `.name` on a plugin config that lacks a `name` key raises this ValueError, because the plugin registry is keyed by name.","triggerScenarios":"Constructing or deserializing a `PluginConfig` (or plain dict wrapped into one) without a `name` entry and then reading `.name`, typically when a plugin config dict was built from partial user input or merged YAML that dropped the field.","commonSituations":"Writing a plugin config inline in YAML and forgetting the `name:` line; a deep-merge or OmegaConf conversion losing the key; code that conditionally sets `name` after construction but reads it before.","solutions":["Add a `name` field to the plugin config, e.g. `quant_config: {name: bnb, ...}`","If building programmatically, set it at construction: `PluginConfig({\"name\": \"lora\", ...})`","Prefer `get_plugin_config()` from `arg_utils` (error 309's path) which validates the field once, early"],"exampleFix":"# before\ncfg = PluginConfig({\"lora_rank\": 16})\nprint(cfg.name)  # ValueError\n\n# after\ncfg = PluginConfig({\"name\": \"lora\", \"lora_rank\": 16})\nprint(cfg.name)  # 'lora'","handlingStrategy":"type-guard","validationCode":"def has_name(cfg: dict) -> bool:\n    return isinstance(cfg, dict) and \"name\" in cfg","typeGuard":"from typing import TypeGuard\n\ndef is_valid_plugin_config(cfg: object) -> TypeGuard[dict]:\n    return isinstance(cfg, dict) and \"name\" in cfg and isinstance(cfg[\"name\"], str)","tryCatchPattern":null,"preventionTips":["Always construct plugin configs through `get_plugin_config()`","Include `name` as the first key in every plugin config template","Validate plugin dicts at config load time, not at attribute access time"],"tags":["v1","plugins","configuration","validation"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}