{"record":{"id":"2d6e5304bca4d045","repo":"plandex-ai/plandex","slug":"error-unmarshalling-convo-message-v","errorCode":null,"errorMessage":"error unmarshalling convo message: %v","messagePattern":"error unmarshalling convo message: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/convo_helpers.go","lineNumber":96,"sourceCode":"\t})\n\n\treturn convo, nil\n}\n\nfunc GetConvoMessage(orgId, planId, messageId string) (*ConvoMessage, error) {\n\tconvoDir := getPlanConversationDir(orgId, planId)\n\n\tfilePath := filepath.Join(convoDir, messageId+\".json\")\n\n\tbytes, err := os.ReadFile(filePath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading convo message: %v\", err)\n\t}\n\n\tvar convoMessage ConvoMessage\n\terr = json.Unmarshal(bytes, &convoMessage)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error unmarshalling convo message: %v\", err)\n\t}\n\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","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/convo_helpers.go#L78-L114","documentation":"GetConvoMessage read the message file but json.Unmarshal could not decode its bytes into a ConvoMessage. This is a data-integrity error indicating the stored JSON is invalid or its schema no longer matches the ConvoMessage struct expected by the running server version.","triggerScenarios":"The message file is truncated/zero-length (interrupted write), manually edited and syntactically invalid, or was written by a different Plandex version whose field types changed (e.g. string vs number, changed object shape) so unmarshal fails on type mismatch.","commonSituations":"Server crash mid-write in StoreConvoMessage; Plandex upgrade/downgrade across a ConvoMessage schema change; operator hand-editing message JSON; corrupted backup restore.","solutions":["Validate the file with 'jq . <convoDir>/<messageId>.json' to pinpoint the JSON error and offset","Repair or restore the message file from backup","Delete the corrupt message file if it can be regenerated (partial replies are often re-storable via StorePartialReply)","Run Plandex's data migration after version upgrades before serving plans","Pin matching client/server versions so stored and expected schemas agree"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"path := filepath.Join(getPlanConversationDir(orgId, planId), messageId+\".json\")\nif data, err := os.ReadFile(path); err == nil {\n    var probe db.ConvoMessage\n    if err := json.Unmarshal(data, &probe); err != nil {\n        return fmt.Errorf(\"message %s is corrupt: %w\", messageId, err)\n    }\n    if probe.Id == \"\" {\n        return fmt.Errorf(\"message %s missing required fields\", messageId)\n    }\n}","typeGuard":"func isValidStoredConvoMessage(data []byte) bool {\n    var m db.ConvoMessage\n    return json.Unmarshal(data, &m) == nil && m.Id != \"\" && !m.CreatedAt.IsZero()\n}","tryCatchPattern":"msg, err := db.GetConvoMessage(orgId, planId, messageId)\nif err != nil {\n    if strings.Contains(err.Error(), \"unmarshalling convo message\") {\n        backupAndQuarantine(path) // then surface as 422/500 data-corruption\n    }\n    return err\n}","preventionTips":["Match server versions to stored data versions (run migrations)","Never truncate writes: use temp-file + rename for storage writes","Keep backups validated with jq before restore","Avoid manual edits to stored message JSON"],"tags":["go","json","unmarshal","data-corruption"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}