{"record":{"id":"4b39689ec4fdf592","repo":"sipeed/picoclaw","slug":"failed-to-parse-security-config-w-4b3968","errorCode":null,"errorMessage":"failed to parse security config: %w","messagePattern":"failed to parse security config: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/security.go","lineNumber":57,"sourceCode":"\tdata, err := os.ReadFile(securityPath)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"failed to read security config: %w\", err)\n\t}\n\n\t// Save existing channels and ModelList before unmarshal\n\tsavedChannels := make(ChannelsConfig, len(cfg.Channels))\n\tfor name, bc := range cfg.Channels {\n\t\tsavedChannels[name] = bc\n\t}\n\t// savedModelList := cfg.ModelList\n\n\t// Parse YAML into a yaml.Node tree to extract channels node\n\tvar rootNode yaml.Node\n\tif err := yaml.Unmarshal(data, &rootNode); err != nil {\n\t\treturn fmt.Errorf(\"failed to parse security config: %w\", err)\n\t}\n\n\t// Extract channels node (support both 'channels' and 'channel_list' keys)\n\tvar channelsNode *yaml.Node\n\tif len(rootNode.Content) > 0 {\n\t\tcontent := rootNode.Content[0].Content\n\t\tfor i := 0; i < len(content); i += 2 {\n\t\t\tif i+1 < len(content) {\n\t\t\t\tkey := content[i].Value\n\t\t\t\tif key == \"channels\" || key == \"channel_list\" {\n\t\t\t\t\tchannelsNode = content[i+1]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Unmarshal non-channel fields from security.yml","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/config/security.go#L39-L75","documentation":"Returned by loadSecurityConfig when the first yaml.Unmarshal of security.yml into a yaml.Node fails — i.e. the file is not syntactically valid YAML at all. The node parse is a pure syntax check before any typed decoding happens, so this error means broken YAML structure: tab indentation, unbalanced quotes/brackets, bad anchors/aliases.","triggerScenarios":"security.yml contains a tab character used for indentation, an unclosed quote or bracket, an undefined YAML alias (`*foo` with no `&foo`), or duplicate keys that the parser rejects. Any of these make yaml.Unmarshal(data, &rootNode) return a syntax error which is wrapped here.","commonSituations":"Hand-editing security.yml in an editor that inserts tabs, pasting YAML from a website/chat that mangles indentation, or truncated files after a crash mid-write. Because the file is written atomically by saveSecurityConfig, corruption almost always comes from manual edits or external tooling.","solutions":["Run a YAML lint/parse check on the file: `yamllint security.yml` or `python -c \"import yaml,sys;yaml.safe_load(open('security.yml'))\"` to get the exact line/column","Replace tabs with spaces for indentation and fix the reported construct (quote, bracket, alias)","Restore from a backup or re-generate security.yml via the app's save/rotate path if hand-repair is impractical","Re-run the config load to confirm the parse succeeds"],"exampleFix":"# before (tab indentation)\nmodel_list:\n\t- model_name: gpt-4o\n\n# after (spaces)\nmodel_list:\n  - model_name: gpt-4o","handlingStrategy":"validation","validationCode":"// Syntax-check security.yml before app startup.\nfunc yamlSyntaxOK(path string) error {\n\tdata, err := os.ReadFile(path)\n\tif err != nil { return err }\n\tvar node yaml.Node\n\treturn yaml.Unmarshal(data, &node)\n}","typeGuard":null,"tryCatchPattern":"if err := loadSecurityConfig(cfg, p); err != nil {\n\tvar yamlErr *yaml.TypeError\n\tif errors.As(err, &yamlErr) {\n\t\t// decode error: fix schema in file\n\t}\n\treturn err // syntax errors surface as wrapped yaml errors; show file+line\n}","preventionTips":["Configure editors to use spaces, never tabs, for YAML","Run yamllint on security.yml in CI","Prefer the app's own save path over hand-editing so files stay well-formed"],"tags":["go","config","yaml","syntax"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}