{"record":{"id":"85667a19be43b7a7","repo":"abiosoft/colima","slug":"error-encoding-yaml-w","errorCode":null,"errorMessage":"error encoding YAML: %w","messagePattern":"error encoding YAML: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/yamlutil/yaml.go","lineNumber":20,"sourceCode":"\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/abiosoft/colima/embedded\"\n\t\"gopkg.in/yaml.v3\"\n)\n\n// WriteYAML encodes struct to file as YAML.\nfunc WriteYAML(value any, file string) error {\n\tb, err := yaml.Marshal(value)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error encoding YAML: %w\", err)\n\t}\n\n\treturn os.WriteFile(file, b, 0644)\n}\n\n// Save saves the config.\nfunc Save(c config.Config, file string) error {\n\tb, err := encodeYAML(c)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := os.WriteFile(file, b, 0644); err != nil {\n\t\treturn fmt.Errorf(\"error writing yaml file: %w\", err)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/abiosoft/colima/blob/c3a5f9184d83a197184f897a9f07eb3c01b3bc88/util/yamlutil/yaml.go#L2-L38","documentation":"WriteYAML (util/yamlutil/yaml.go:20) marshals an arbitrary Go value with yaml.v3 and wraps a Marshal failure. yaml.v3 only fails to marshal values Go cannot represent in YAML: channels, functions, cyclic data structures, or types whose custom MarshalYAML returns an error. colima's own config structs never contain such types, so this error almost always comes from third-party code reusing WriteYAML with a richer value.","triggerScenarios":"Calling util.WriteYAML(value, file) where value embeds a chan or func field, a self-referencing pointer graph, or a type with a broken MarshalYAML method.","commonSituations":"Embedding colima as a library in other tooling and persisting runtime structs; copying a struct that gained a func/chan field during refactoring; custom types with constructors injecting loggers/cancellations into otherwise-serializable structs.","solutions":["Marshal a dedicated DTO that excludes chan/func fields (loggers, cancels, locks)","Implement yaml.Marshaler on the offending type or add `yaml:\"-\"` tags to skip those fields","Break cycles by omitting back-references before serializing","Log the wrapped cause — it names the exact type yaml choked on"],"exampleFix":"// before\ntype state struct {\n    Name string\n    Done chan struct{} // yaml.Marshal fails\n}\nutil.WriteYAML(state{...}, \"s.yaml\")\n\n// after\ntype stateDTO struct {\n    Name string `yaml:\"name\"`\n}\nutil.WriteYAML(stateDTO{Name: s.Name}, \"s.yaml\")","handlingStrategy":"validation","validationCode":"// reject values containing chan/func fields before marshaling\nfunc marshalable(v any) bool {\n    t := reflect.TypeOf(v)\n    for t != nil && (t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice || t.Kind() == reflect.Array || t.Kind() == reflect.Map) {\n        t = t.Elem()\n    }\n    if t == nil { return true }\n    for i := 0; i < t.NumField(); i++ {\n        switch t.Field(i).Type.Kind() {\n        case reflect.Chan, reflect.Func, reflect.UnsafePointer:\n            return false\n        }\n    }\n    return true\n}","typeGuard":"func isTypeError(err error) bool {\n    s := err.Error()\n    return strings.Contains(s, \"cannot marshal type\") || strings.Contains(s, \"unsupported type\")\n}","tryCatchPattern":"if err := util.WriteYAML(value, path); err != nil {\n    if isTypeError(err) {\n        // strip chan/func fields into a DTO and write that instead\n        return writeDTO(value, path)\n    }\n    return fmt.Errorf(\"persisting %s: %w\", path, err)\n}","preventionTips":["Keep persisted structs data-only; keep loggers/cancels in separate runtime objects","Tag non-serialized fields with `yaml:\"-\"`","Unit-test serialization of every type passed to WriteYAML","Implement yaml.Marshaler deliberately for custom types"],"tags":["yaml","serialization","types"],"backgroundTag":null,"analyzedSha":"c3a5f9184d83a197184f897a9f07eb3c01b3bc88","analyzedAt":"2026-08-15T18:58:08.334Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}