abiosoft/colima · error
error encoding YAML: %w
Error message
error encoding YAML: %w
What it means
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.
Source
Thrown at util/yamlutil/yaml.go:20
import (
"bytes"
"fmt"
"os"
"reflect"
"strconv"
"strings"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/embedded"
"gopkg.in/yaml.v3"
)
// WriteYAML encodes struct to file as YAML.
func WriteYAML(value any, file string) error {
b, err := yaml.Marshal(value)
if err != nil {
return fmt.Errorf("error encoding YAML: %w", err)
}
return os.WriteFile(file, b, 0644)
}
// Save saves the config.
func Save(c config.Config, file string) error {
b, err := encodeYAML(c)
if err != nil {
return err
}
if err := os.WriteFile(file, b, 0644); err != nil {
return fmt.Errorf("error writing yaml file: %w", err)
}
return nil
}
View on GitHub (pinned to c3a5f9184d)
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
Example fix
// before
type state struct {
Name string
Done chan struct{} // yaml.Marshal fails
}
util.WriteYAML(state{...}, "s.yaml")
// after
type stateDTO struct {
Name string `yaml:"name"`
}
util.WriteYAML(stateDTO{Name: s.Name}, "s.yaml") Defensive patterns
Strategy: validation
Validate before calling
// reject values containing chan/func fields before marshaling
func marshalable(v any) bool {
t := reflect.TypeOf(v)
for t != nil && (t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice || t.Kind() == reflect.Array || t.Kind() == reflect.Map) {
t = t.Elem()
}
if t == nil { return true }
for i := 0; i < t.NumField(); i++ {
switch t.Field(i).Type.Kind() {
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
return false
}
}
return true
} Type guard
func isTypeError(err error) bool {
s := err.Error()
return strings.Contains(s, "cannot marshal type") || strings.Contains(s, "unsupported type")
} Try / catch
if err := util.WriteYAML(value, path); err != nil {
if isTypeError(err) {
// strip chan/func fields into a DTO and write that instead
return writeDTO(value, path)
}
return fmt.Errorf("persisting %s: %w", path, err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- error marshalling Lima network config file: %w
- unexpected error nested value encoding: %w
- error running %s provision script(s)
- error in config file: %w
- config load failed: %w
AI-assisted analysis of abiosoft/colima@c3a5f9184d (2026-08-15).
Data as JSON: /api/errors/85667a19be43b7a7.
Report an issue: GitHub.