{"record":{"id":"1f6464e811c25744","repo":"lima-vm/lima","slug":"failed-to-marshal-as-yaml-v-w","errorCode":null,"errorMessage":"failed to marshal as YAML: %+v: %w","messagePattern":"failed to marshal as YAML: %\\+v: %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/textutil/textutil.go","lineNumber":70,"sourceCode":"\treturn text\n}\n\n// TemplateFuncMap is a text/template FuncMap.\nvar TemplateFuncMap = template.FuncMap{\n\t\"json\": func(v any) string {\n\t\tvar b bytes.Buffer\n\t\tenc := json.NewEncoder(&b)\n\t\tenc.SetEscapeHTML(false)\n\t\tif err := enc.Encode(v); err != nil {\n\t\t\tpanic(fmt.Errorf(\"failed to marshal as JSON: %+v: %w\", v, err))\n\t\t}\n\t\treturn strings.TrimSuffix(b.String(), \"\\n\")\n\t},\n\t\"yaml\": func(v any) string {\n\t\tvar b bytes.Buffer\n\t\tenc := yaml.NewEncoder(&b)\n\t\tif err := enc.Encode(v); err != nil {\n\t\t\tpanic(fmt.Errorf(\"failed to marshal as YAML: %+v: %w\", v, err))\n\t\t}\n\t\treturn \"---\\n\" + strings.TrimSuffix(b.String(), \"\\n\")\n\t},\n\t\"indent\": func(a ...any) (string, error) {\n\t\tif len(a) == 0 {\n\t\t\treturn \"\", errors.New(\"function takes at least one string argument\")\n\t\t}\n\t\tif len(a) > 2 {\n\t\t\treturn \"\", errors.New(\"function takes at most 2 arguments\")\n\t\t}\n\t\tvar ok bool\n\t\tsize := 2\n\t\tif len(a) > 1 {\n\t\t\tif size, ok = a[0].(int); !ok {\n\t\t\t\treturn \"\", errors.New(\"optional first argument must be an integer\")\n\t\t\t}\n\t\t}\n\t\ttext := \"\"","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/lima-vm/lima/blob/dd909d0973cd84fa35f9e1693181b4585ea616c1/pkg/textutil/textutil.go#L52-L88","documentation":"The \"yaml\" template function encodes its argument with goccy/go-yaml and panics if the encoder fails, wrapping the value and underlying error. The panic propagates through text/template execution, aborting template rendering. YAML marshaling of plain Go data rarely fails, but goccy/go-yaml enforces type constraints (e.g. unsupported map key types, invalid values for time/encoding) that trigger this.","triggerScenarios":"Executing a template that calls `{{yaml v}}` where v's type graph cannot be encoded by goccy/go-yaml, such as maps with non-string/int key types the encoder rejects, or values whose MarshalYAML implementation returns an error.","commonSituations":"Rendering Lima YAML snippets from config objects containing maps keyed by structs or other exotic key types; a custom type with a faulty MarshalYAML used in template data; version upgrades of goccy/go-yaml tightening encoder checks.","solutions":["Read the wrapped error to find the offending type/value; convert map keys to string (or int) before rendering.","Replace exotic key types with map[string]any or a slice of key/value structs in the data passed to the template.","Fix or bypass a custom MarshalYAML that returns an error for this value.","Marshal with yaml.Marshal at the call site (handling the error) instead of using the panicking `yaml` template function."],"exampleFix":"// before (map key is a struct -> encoder error)\ndata := map[Key]string{...}\ntmpl.Execute(w, data) // {{yaml .}}\n// after\nm := map[string]string{}\nfor k, v := range data { m[k.String()] = v }\ntmpl.Execute(w, m)","handlingStrategy":"try-catch","validationCode":"if _, err := yaml.Marshal(v); err != nil {\n    // convert map keys to string or fix MarshalYAML before rendering\n}","typeGuard":"func yamlSafeMap(m any) (map[string]any, bool) {\n    switch t := m.(type) {\n    case map[string]any:\n        return t, true\n    case map[any]any:\n        out := make(map[string]any, len(t))\n        for k, v := range t {\n            ks, ok := k.(string)\n            if !ok { return nil, false }\n            out[ks] = v\n        }\n        return out, true\n    }\n    return nil, false\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        if strings.Contains(fmt.Sprint(r), \"failed to marshal as YAML\") {\n            err = fmt.Errorf(\"template data not YAML-encodable: %v\", r)\n        }\n    }\n}()\nb, err = textutil.ExecuteTemplate(tmpl, data)","preventionTips":["Use string (or int) map keys; avoid struct-typed keys that goccy/go-yaml rejects.","Test custom MarshalYAML implementations for the values you render.","Pre-marshal with yaml.Marshal at the call site when data shapes are uncertain.","Pin/verify goccy/go-yaml behavior when upgrading dependencies."],"tags":["yaml","templates","panic","serialization"],"backgroundTag":"yaml-marshal-failed","analyzedSha":"dd909d0973cd84fa35f9e1693181b4585ea616c1","analyzedAt":"2026-09-01T14:24:59.842Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}