{"record":{"id":"4166fea87e9604f1","repo":"plandex-ai/plandex","slug":"error-marshalling-plan-convo","errorCode":null,"errorMessage":"Error marshalling plan convo: ","messagePattern":"Error marshalling plan convo: ","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/plans_convo.go","lineNumber":72,"sourceCode":"\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\tlog.Println(\"Error getting plan convo: \", err)\n\t\thttp.Error(w, \"Error getting plan convo: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tapiConvoMessages := make([]*shared.ConvoMessage, len(convoMessages))\n\tfor i, convoMessage := range convoMessages {\n\t\tapiConvoMessages[i] = convoMessage.ToApi()\n\t}\n\n\tbytes, err := json.Marshal(apiConvoMessages)\n\n\tif err != nil {\n\t\tlog.Println(\"Error marshalling plan convo: \", err)\n\t\thttp.Error(w, \"Error marshalling plan convo: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tlog.Println(\"Successfully processed request for ListConvoHandler\")\n\tw.Write(bytes)\n\n}\n\nfunc GetPlanStatusHandler(w http.ResponseWriter, r *http.Request) {\n\tlog.Println(\"Received a request for GetPlanStatusHandler\")\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\"]","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_convo.go#L54-L90","documentation":"ListConvoHandler returns this 500 when json.Marshal fails to serialize the []*shared.ConvoMessage slice after the convo was fetched successfully. Like any Marshal failure this points to unsupported field types or a failing custom MarshalJSON, which should not occur with normal ConvoMessage data — it usually means a schema/code change introduced something unserializable.","triggerScenarios":"json.Marshal(apiConvoMessages) errors — only realistic if ConvoMessage or its ToApi() output gains an unsupported type (channel, func, cyclic reference) or a field's MarshalJSON returns an error.","commonSituations":"Recent change to shared.ConvoMessage added a non-serializable field or a custom marshaller that errors; corrupted data feeding a cyclic pointer.","solutions":["Check the server log for the marshal error detail","Inspect shared.ConvoMessage and ToApi() for newly added unsupported field types","Add a regression test marshalling a real ConvoMessage","If a field is problematic, mark it json:\"-\" or convert it to a serializable representation"],"exampleFix":"// before\nCreatedAt customTime // type with failing MarshalJSON\n// after\nCreatedAt time.Time `json:\"createdAt\"` // use standard time.Time","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isConvoMessageSerializable(m) {\n  return typeof m === 'object' && m !== null\n    && typeof m.id === 'string'\n    && (typeof m.text === 'string' || m.text == null);\n}","tryCatchPattern":"try {\n  const convo = await listPlanConvo(planId, branch);\n} catch (e) {\n  if (/Error marshalling plan convo/.test(e.message)) {\n    log.error('Server-side serialization defect in ConvoMessage — report to maintainers');\n  }\n  throw e;\n}","preventionTips":["Keep shared.ConvoMessage fields JSON-serializable","Add regression tests marshalling real convo messages","Never attach runtime-only handles (channels, funcs) to API models","Validate ToApi() output shapes in CI"],"tags":["http-500","json","serialization"],"backgroundTag":"json-marshalling-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}