lima-vm/lima · error

failed to marshal as YAML: %+v: %w

Error message

failed to marshal as YAML: %+v: %w

What it means

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.

Source

Thrown at pkg/textutil/textutil.go:70

	return text
}

// TemplateFuncMap is a text/template FuncMap.
var TemplateFuncMap = template.FuncMap{
	"json": func(v any) string {
		var b bytes.Buffer
		enc := json.NewEncoder(&b)
		enc.SetEscapeHTML(false)
		if err := enc.Encode(v); err != nil {
			panic(fmt.Errorf("failed to marshal as JSON: %+v: %w", v, err))
		}
		return strings.TrimSuffix(b.String(), "\n")
	},
	"yaml": func(v any) string {
		var b bytes.Buffer
		enc := yaml.NewEncoder(&b)
		if err := enc.Encode(v); err != nil {
			panic(fmt.Errorf("failed to marshal as YAML: %+v: %w", v, err))
		}
		return "---\n" + strings.TrimSuffix(b.String(), "\n")
	},
	"indent": func(a ...any) (string, error) {
		if len(a) == 0 {
			return "", errors.New("function takes at least one string argument")
		}
		if len(a) > 2 {
			return "", errors.New("function takes at most 2 arguments")
		}
		var ok bool
		size := 2
		if len(a) > 1 {
			if size, ok = a[0].(int); !ok {
				return "", errors.New("optional first argument must be an integer")
			}
		}
		text := ""

View on GitHub (pinned to dd909d0973)

Solutions

  1. Read the wrapped error to find the offending type/value; convert map keys to string (or int) before rendering.
  2. Replace exotic key types with map[string]any or a slice of key/value structs in the data passed to the template.
  3. Fix or bypass a custom MarshalYAML that returns an error for this value.
  4. Marshal with yaml.Marshal at the call site (handling the error) instead of using the panicking `yaml` template function.

Example fix

// before (map key is a struct -> encoder error)
data := map[Key]string{...}
tmpl.Execute(w, data) // {{yaml .}}
// after
m := map[string]string{}
for k, v := range data { m[k.String()] = v }
tmpl.Execute(w, m)
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := yaml.Marshal(v); err != nil {
    // convert map keys to string or fix MarshalYAML before rendering
}

Type guard

func yamlSafeMap(m any) (map[string]any, bool) {
    switch t := m.(type) {
    case map[string]any:
        return t, true
    case map[any]any:
        out := make(map[string]any, len(t))
        for k, v := range t {
            ks, ok := k.(string)
            if !ok { return nil, false }
            out[ks] = v
        }
        return out, true
    }
    return nil, false
}

Try / catch

defer func() {
    if r := recover(); r != nil {
        if strings.Contains(fmt.Sprint(r), "failed to marshal as YAML") {
            err = fmt.Errorf("template data not YAML-encodable: %v", r)
        }
    }
}()
b, err = textutil.ExecuteTemplate(tmpl, data)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01). Data as JSON: /api/errors/1f6464e811c25744. Report an issue: GitHub.