{"record":{"id":"754fa0f4afa64ae7","repo":"lima-vm/lima","slug":"failed-to-marshal-as-json-v-w","errorCode":null,"errorMessage":"failed to marshal as JSON: %+v: %w","messagePattern":"failed to marshal as JSON: %\\+v: %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/textutil/textutil.go","lineNumber":62,"sourceCode":"\treturn PrefixString(prefix, text)\n}\n\n// MissingString returns message if the text is empty.\nfunc MissingString(message, text string) string {\n\tif text == \"\" {\n\t\treturn message\n\t}\n\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}","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/lima-vm/lima/blob/dd909d0973cd84fa35f9e1693181b4585ea616c1/pkg/textutil/textutil.go#L44-L80","documentation":"The \"json\" template function in textutil.TemplateFuncMap encodes its argument with encoding/json and panics if json.Encoder.Encode fails. Because text/template function panics propagate out of template execution, this error surfaces as a panic (recovered as an execution error by template.Execute) wrapped with the offending value and the underlying marshal error. JSON encoding of in-memory values essentially only fails for unsupported types (channels, funcs, complex numbers) or cyclic data.","triggerScenarios":"Executing a text/template (via textutil.ExecuteTemplate or any template using TemplateFuncMap) that calls `{{json v}}` where v contains a value json cannot encode: a channel, function, complex number, an invalid UTF-8 string (skipped, not an error), or most commonly a data cycle causing \"json: unsupported value\" / \"encountered a cycle via ...\".","commonSituations":"Passing a struct with func or chan fields into a template that emits it with {{json .}}; templates rendering Lima config objects that gained a non-serializable field; hand-built maps containing callbacks used inside provisioning templates.","solutions":["Inspect the wrapped error message to identify the unsupported field/value, then remove it or change its type before rendering (e.g. use a plain string or []byte instead of a func/chan field).","Break data cycles: build an acyclic view (copy needed fields into a map/struct without back-pointers) before passing it to the template.","Implement json.Marshaler on the offending type to emit a serializable representation.","If you control the call site, prefer executing the template step inside a recover, or marshal the value yourself with json.Marshal and handle the error instead of using the panicking template func."],"exampleFix":"// before (panics: Inst has a chan field)\ntmpl.Execute(w, inst) // template: {{json .Inst}}\n// after\nview := map[string]any{\"name\": inst.Name, \"dir\": inst.Dir}\ntmpl.Execute(w, view) // {{json .}} works","handlingStrategy":"try-catch","validationCode":"if _, err := json.Marshal(v); err != nil {\n    // sanitize v (drop funcs/chans, break cycles) before rendering the template\n}","typeGuard":"func jsonSafe(v any) bool {\n    switch v.(type) {\n    case chan any, func(), complex64, complex128, map[any]any:\n        return false\n    }\n    return true\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        if strings.Contains(fmt.Sprint(r), \"failed to marshal as JSON\") {\n            err = fmt.Errorf(\"template data not JSON-serializable: %v\", r)\n        }\n    }\n}()\nb, err = textutil.ExecuteTemplate(tmpl, data)","preventionTips":["Only pass JSON-serializable data (no chan/func fields, no cycles) into templates that use {{json}}.","Pre-marshal risky values with json.Marshal and pass the resulting string into the template.","Keep template data as plain maps/structs of primitives.","Always call ExecuteTemplate with error handling; template panics surface as execution errors."],"tags":["json","templates","panic","serialization"],"backgroundTag":"json-unsupported-type","analyzedSha":"dd909d0973cd84fa35f9e1693181b4585ea616c1","analyzedAt":"2026-09-01T14:24:59.842Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}