{"record":{"id":"2fa90b554a7a5cbc","repo":"plandex-ai/plandex","slug":"no-convo-message-for-id-s","errorCode":null,"errorMessage":"no convo message for ID: %s","messagePattern":"no convo message for ID: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/types/active_plan_pending_builds.go","lineNumber":49,"sourceCode":"\t}\n\n\tconvoMessagesById := map[string]*db.ConvoMessage{}\n\tfor _, msg := range convoMessages {\n\t\tconvoMessagesById[msg.Id] = msg\n\t}\n\n\tactiveBuildsByPath := map[string][]*ActiveBuild{}\n\n\tfor _, desc := range planDescs {\n\t\tif (!desc.DidBuild && len(desc.Operations) > 0) || len(desc.BuildPathsInvalidated) > 0 {\n\t\t\tif desc.ConvoMessageId == \"\" {\n\t\t\t\tlog.Printf(\"No convo message ID for description: %v\\n\", desc)\n\t\t\t\treturn nil, fmt.Errorf(\"no convo message ID for description: %v\", desc)\n\t\t\t}\n\n\t\t\tif convoMessagesById[desc.ConvoMessageId] == nil {\n\t\t\t\tlog.Printf(\"No convo message for ID: %s\\n\", desc.ConvoMessageId)\n\t\t\t\treturn nil, fmt.Errorf(\"no convo message for ID: %s\", desc.ConvoMessageId)\n\t\t\t}\n\n\t\t\t// convoMessage := convoMessagesById[desc.ConvoMessageId]\n\n\t\t\t// replyParser := NewReplyParser()\n\t\t\t// replyParser.AddChunk(convoMessage.Message, false)\n\t\t\t// parserRes := replyParser.FinishAndRead()\n\n\t\t\tnumAdded := 0\n\t\t\tfor _, op := range desc.Operations {\n\n\t\t\t\tif desc.DidBuild && !desc.BuildPathsInvalidated[op.Path] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif activeBuildsByPath[op.Path] == nil {\n\t\t\t\t\tactiveBuildsByPath[op.Path] = []*ActiveBuild{}\n\t\t\t\t}","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/types/active_plan_pending_builds.go#L31-L67","documentation":"Thrown when a description's ConvoMessageId is set but no message with that ID was found among the loaded conversation messages (convoMessagesById lookup returns nil). It means the description points at a message that does not exist in the plan's convo.","triggerScenarios":"db.GetConvoMessageDescriptions returns a description whose convo_message_id has no matching row in the convo messages table; passing a partial convoMessagesArg that omits the referenced message; messages deleted after descriptions were created.","commonSituations":"Orphaned description rows after convo message deletion or plan truncation; cross-plan data corruption from a bad migration; caller passing a filtered/partial convo message slice to PendingBuildsByPath.","solutions":["Look up the logged ConvoMessageId in the convo_messages table to confirm whether the row was deleted.","Restore the missing convo message or delete the orphaned description record.","If supplying convoMessagesArg, ensure it contains ALL messages for the plan (e.g. the full result of db.GetPlanConvo).","Re-run any migration/backfill that links descriptions to their source messages."],"exampleFix":"// before\nbuilds, err := plan.PendingBuildsByPath(orgId, userId, partialConvo)\n// after\nfullConvo, err := db.GetPlanConvo(orgId, plan.Id) // pass the complete set\nif err != nil { return err }\nbuilds, err := plan.PendingBuildsByPath(orgId, userId, fullConvo)","handlingStrategy":"validation","validationCode":"msgIds := map[string]bool{}\nfor _, m := range convo { msgIds[m.Id] = true }\nfor _, desc := range descs {\n    if desc.ConvoMessageId != \"\" && !msgIds[desc.ConvoMessageId] {\n        return fmt.Errorf(\"description %s references missing convo message %s\", desc.Id, desc.ConvoMessageId)\n    }\n}","typeGuard":"func convoMessageExists(id string, byId map[string]*db.ConvoMessage) bool {\n    return id != \"\" && byId[id] != nil\n}","tryCatchPattern":"builds, err := plan.PendingBuildsByPath(orgId, userId, fullConvo)\nif err != nil {\n    if strings.Contains(err.Error(), \"no convo message for ID\") {\n        log.Printf(\"dangling description reference; resync descriptions with convo\")\n        return resyncDescriptions(plan.Id)\n    }\n    return err\n}","preventionTips":["Cascade-delete descriptions when their convo messages are removed (FK with ON DELETE CASCADE).","Never pass partial convo slices as convoMessagesArg; pass the full GetPlanConvo result.","Validate referential integrity between descriptions and convo messages after migrations.","Detect and prune orphaned descriptions in a periodic integrity job."],"tags":["data-integrity","go","dangling-reference"],"backgroundTag":"dangling-foreign-key","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"}