{"record":{"id":"6c0653c91e643d5f","repo":"plandex-ai/plandex","slug":"error-marshalling-convo-message-v","errorCode":null,"errorMessage":"error marshalling convo message: %v","messagePattern":"error marshalling convo message: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/convo_helpers.go","lineNumber":116,"sourceCode":"\n\treturn &convoMessage, nil\n}\n\nfunc StoreConvoMessage(repo *GitRepo, message *ConvoMessage, currentUserId, branch string, commit bool) (string, error) {\n\tconvoDir := getPlanConversationDir(message.OrgId, message.PlanId)\n\n\tts := time.Now().UTC()\n\n\tif message.Id == \"\" {\n\t\tmessage.Id = uuid.New().String()\n\t}\n\n\tmessage.CreatedAt = ts\n\n\tbytes, err := json.Marshal(message)\n\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error marshalling convo message: %v\", err)\n\t}\n\n\terr = os.MkdirAll(convoDir, os.ModePerm)\n\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error creating convo dir: %v\", err)\n\t}\n\n\terr = os.WriteFile(filepath.Join(convoDir, message.Id+\".json\"), bytes, os.ModePerm)\n\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error writing convo message: %v\", err)\n\t}\n\n\terr = AddPlanConvoMessage(message, branch)\n\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error adding convo tokens: %v\", err)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/convo_helpers.go#L98-L134","documentation":"StoreConvoMessage serializes the ConvoMessage to JSON with json.Marshal before persisting it; failure here returns this error and nothing is written. json.Marshal on a struct like this essentially only fails if the message contains values that cannot be represented in JSON (channels, funcs, invalid UTF-8 in strings, or a custom MarshalJSON returning an error).","triggerScenarios":"json.Marshal(message) returns an error because a field of ConvoMessage (or a nested struct implementing MarshalJSON) is unmarshalable — e.g. a field was changed to chan/func type during development, a custom marshaller on a nested type errored, or a string field contains invalid UTF-8 from upstream model output.","commonSituations":"Custom code or a fork added a non-serializable field to ConvoMessage; a model/provider response with invalid UTF-8 got copied into message.Message; a plugin/middleware type with a failing MarshalJSON was embedded.","solutions":["Log the full %v error — json.Marshal errors name the exact field/type that failed","Remove or fix the non-serializable field on ConvoMessage (chan, func, unsafe pointer)","Sanitize string fields (e.g. utf8.ValidString / strings.ToValidUTF8) before assigning model output","Ensure any custom MarshalJSON implementations are nil-safe and error-free","Write a unit test marshalling a fully-populated ConvoMessage to catch regressions"],"exampleFix":"// before\nmessage.Message = modelRawOutput\nbytes, err := json.Marshal(message)\n// after\nmessage.Message = strings.ToValidUTF8(modelRawOutput, \"\\ufffd\")\nbytes, err := json.Marshal(message)","handlingStrategy":"type-guard","validationCode":"func marshalableConvoMessage(m *db.ConvoMessage) error {\n    var probe db.ConvoMessage = *m\n    _, err := json.Marshal(&probe)\n    return err\n}\n// call before StoreConvoMessage\nif err := marshalableConvoMessage(msg); err != nil { /* fix field */ }","typeGuard":"func isUTF8Safe(s string) bool { return utf8.ValidString(s) }","tryCatchPattern":"id, err := db.StoreConvoMessage(repo, msg, userId, branch, true)\nif err != nil {\n    if strings.Contains(err.Error(), \"marshalling convo message\") {\n        // non-serializable field — log msg fields, fix input, do not retry blindly\n        log.Printf(\"unserializable convo message fields: %+v\", msg)\n        return errSanitizeAndResend\n    }\n    return err\n}","preventionTips":["Sanitize model output to valid UTF-8 before assigning to message fields","Keep ConvoMessage free of chan/func/custom-marshaler fields","Unit test json.Marshal on a fully-populated ConvoMessage in CI","Run go vet for JSON tag issues on the struct"],"tags":["go","json","marshal","serialization"],"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-14T00:17:10.932Z"}