{"record":{"id":"893d7cfae35d350a","repo":"plandex-ai/plandex","slug":"error-marshalling-contexts","errorCode":null,"errorMessage":"Error marshalling contexts: ","messagePattern":"Error marshalling contexts: ","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/plans_context.go","lineNumber":73,"sourceCode":"\t})\n\n\tif err != nil {\n\t\tlog.Printf(\"Error getting contexts: %v\\n\", err)\n\t\thttp.Error(w, \"Error getting contexts: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tvar apiContexts []*shared.Context\n\n\tfor _, dbContext := range dbContexts {\n\t\tapiContexts = append(apiContexts, dbContext.ToApi())\n\t}\n\n\tbytes, err := json.Marshal(apiContexts)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error marshalling contexts: %v\\n\", err)\n\t\thttp.Error(w, \"Error marshalling contexts: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tw.Write(bytes)\n}\n\nfunc GetContextBodyHandler(w http.ResponseWriter, r *http.Request) {\n\tlog.Println(\"Received request for GetContextBodyHandler\")\n\n\tauth := Authenticate(w, r, true)\n\tif auth == nil {\n\t\treturn\n\t}\n\n\tvars := mux.Vars(r)\n\tplanId := vars[\"planId\"]\n\tbranch := vars[\"branch\"]\n\tcontextId := vars[\"contextId\"]","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_context.go#L55-L91","documentation":"After converting db contexts to API contexts, ListContextHandler json.Marshal's the []*shared.Context slice. Marshal only fails here if a Context field holds an unsupported type (e.g. channel, func, or cyclic data). In practice this is nearly impossible with fixed DB-backed structs, so the error signals an unexpected data/model problem, returned as HTTP 500.","triggerScenarios":"json.Marshal(apiContexts) returns an error — an unsupported value in shared.Context (channel/func/cycle) introduced by a code or model change.","commonSituations":"A recent code change added an unserializable field to shared.Context or db.Context.ToApi(); custom build with modified model types.","solutions":["Read err.Error() — Go names the exact unsupported type and struct field","Check recent changes to shared.Context / db.Context.ToApi() for unserializable fields (func, chan, cycles)","Add json:\"-\" tags to fields that must not be serialized, or give them custom MarshalJSON","Rebuild/redeploy from a known-good release to confirm it's a code-level issue"],"exampleFix":"// before\ntype Context struct {\n\tloader func() error // unsupported by json.Marshal\n\t...\n}\n// after\ntype Context struct {\n\tloader func() error `json:\"-\"`\n\t...\n}","handlingStrategy":"type-guard","validationCode":"func marshalable(v any) bool {\n\tb, err := json.Marshal(v)\n\treturn err == nil && b != nil\n}","typeGuard":"func hasUnsupportedFields(v reflect.Value, seen map[uintptr]bool) bool {\n\tswitch v.Kind() {\n\tcase reflect.Chan, reflect.Func:\n\t\treturn true\n\tcase reflect.Ptr, reflect.Map:\n\t\tif v.IsNil() { return false }\n\t\tif seen[v.Pointer()] { return true }\n\t\tseen[v.Pointer()] = true\n\t\tdefer delete(seen, v.Pointer())\n\t}\n\tswitch v.Kind() {\n\tcase reflect.Struct:\n\t\tfor i := 0; i < v.NumField(); i++ {\n\t\t\tif hasUnsupportedFields(v.Field(i), seen) { return true }\n\t\t}\n\tcase reflect.Slice, reflect.Array:\n\t\tfor i := 0; i < v.Len(); i++ {\n\t\t\tif hasUnsupportedFields(v.Index(i), seen) { return true }\n\t\t}\n\t}\n\treturn false\n}","tryCatchPattern":"bytes, err := json.Marshal(apiContexts)\nif err != nil {\n\tlog.Printf(\"Error marshalling contexts: %v\", err)\n\thttp.Error(w, \"Error marshalling contexts\", http.StatusInternalServerError)\n\treturn\n}","preventionTips":["Never add chan/func/cyclic fields to API response structs, or tag them json:\"-\"","Add a CI test that marshals representative response values","Keep shared API types in sync between client and server builds"],"tags":["go","json","serialization","http-500"],"backgroundTag":"json-marshal-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}