{"record":{"id":"fcc98ed3dde1b250","repo":"router-for-me/CLIProxyAPI","slug":"parse-plugin-enabled-w","errorCode":null,"errorMessage":"parse plugin enabled: %w","messagePattern":"parse plugin enabled: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/config_types.go","lineNumber":67,"sourceCode":"\t\treturn nil\n\t}\n\n\tc.Raw = *deepCopyNode(value)\n\tif value.Kind != yaml.MappingNode {\n\t\treturn nil\n\t}\n\n\tfor i := 0; i+1 < len(value.Content); i += 2 {\n\t\tkey := value.Content[i]\n\t\tnode := value.Content[i+1]\n\t\tif key == nil {\n\t\t\tcontinue\n\t\t}\n\t\tswitch key.Value {\n\t\tcase \"enabled\":\n\t\t\tvar enabled bool\n\t\t\tif errDecodeEnabled := node.Decode(&enabled); errDecodeEnabled != nil {\n\t\t\t\treturn fmt.Errorf(\"parse plugin enabled: %w\", errDecodeEnabled)\n\t\t\t}\n\t\t\tc.Enabled = &enabled\n\t\tcase \"priority\":\n\t\t\tvar priority int\n\t\t\tif errDecodePriority := node.Decode(&priority); errDecodePriority != nil {\n\t\t\t\treturn fmt.Errorf(\"parse plugin priority: %w\", errDecodePriority)\n\t\t\t}\n\t\t\tc.Priority = priority\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// MarshalYAML returns the preserved raw plugin YAML subtree for lossless config output.\nfunc (c PluginInstanceConfig) MarshalYAML() (any, error) {\n\tif c.Raw.Kind == 0 {\n\t\treturn defaultPluginInstanceConfigNode(), nil","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/config_types.go#L49-L85","documentation":"Thrown while decoding the 'enabled' field of a plugin instance in config.yaml. PluginInstanceConfig uses a custom UnmarshalYAML that walks the yaml.Node pair-by-pair; when the value under the 'enabled' key cannot be decoded into a Go bool, this wrapped error is returned. The %w chain carries the underlying gopkg.in/yaml.v3 type error (e.g. 'cannot unmarshal !!str into bool').","triggerScenarios":"A plugins: section in config.yaml where a plugin instance sets enabled to a non-boolean, e.g. 'plugins:\\n  configs:\\n    myplugin:\\n      enabled: \"yes\"' or 'enabled: 1' or 'enabled: on/off' (YAML 1.2 core schema does not coerce these strings to bool). Also triggered by an empty scalar '~' or a nested map under 'enabled'.","commonSituations":"Copying a plugin block from documentation that used quoted strings; migrating from a config format that accepted 'yes'/'no'; editing config.yaml by hand while the file watcher hot-reloads a half-finished edit; using a YAML linter that auto-quotes booleans as strings.","solutions":["Open config.yaml, find the plugins section, and set enabled to a bare true or false (unquoted).","Remove quotes around the value: change enabled: \"true\" to enabled: true.","If the value was 'yes'/'no'/'on'/'off'/'1'/'0', replace it with true/false.","Validate the file with a YAML parser or 'go run ./cmd/server --config config.yaml' before deploying.","If you generate the config programmatically, ensure the field is emitted as a bool, not a string."],"exampleFix":"# before (config.yaml)\nplugins:\n  configs:\n    myplugin:\n      enabled: \"yes\"\n\n# after\nplugins:\n  configs:\n    myplugin:\n      enabled: true","handlingStrategy":"validation","validationCode":"// Go: verify plugin enabled values are plain booleans before loading config.\nimport (\n    \"os\"\n    \"gopkg.in/yaml.v3\"\n)\n\nfunc pluginEnabledValid(path string) (bool, error) {\n    data, err := os.ReadFile(path)\n    if err != nil {\n        return false, err\n    }\n    var root map[string]any\n    if err := yaml.Unmarshal(data, &root); err != nil {\n        return false, err\n    }\n    plugins, ok := root[\"plugins\"].(map[string]any)\n    if !ok {\n        return true, nil // no plugins section\n    }\n    walkConfigs(plugins) // check every \"enabled\" under plugins.configs.*\n    return true, nil\n}\n\nfunc walkConfigs(m map[string]any) {\n    for _, v := range m {\n        if inst, ok := v.(map[string]any); ok {\n            if enabled, exists := inst[\"enabled\"]; exists {\n                if _, isBool := enabled.(bool); !isBool {\n                    panic(\"plugin enabled must be a bare true/false\")\n                }\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always write enabled: true/false unquoted in config.yaml.","Never use yes/no/on/off/1/0 for booleans — YAML 1.2 keeps them as strings.","Run a YAML schema lint on config.yaml in CI.","Avoid saving config mid-edit when the hot-reload watcher is active."],"tags":["config","yaml","plugins","parsing"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}