fix(job): guard group conversation in MixinJob.createConversation#6416
Open
SeniorZhai wants to merge 2 commits into
Open
fix(job): guard group conversation in MixinJob.createConversation#6416SeniorZhai wants to merge 2 commits into
SeniorZhai wants to merge 2 commits into
Conversation
…nExist The createConversation path in MixinJob builds a minimal ConversationRequest without random_id, name, announcement, or full participants. When a GROUP conversation falls into SendMessageJob's checkConversationExist with a non-SUCCESS status, it triggers /conversations create with category=GROUP but no random_id, which the server rejects (missing or invalid UUID). Short-circuit groups here so creation stays on the proper flow via GroupViewModel / ConversationListViewModel.createGroupConversation, which always supplies a valid randomId.
createConversation builds a minimal ConversationRequest without random_id, name, or full participants, which is only valid for CONTACT (1v1) where the conversationId is deterministically derived from two userIds. If a GROUP slips into this path (e.g. SendMessageJob.checkConversationExist on a non-SUCCESS local group), the /conversations POST hits the server with category=GROUP but no random_id, yielding 'invalid UUID' or missing-param errors and a broken group on the server. Bail out early for groups and report the unexpected state so the proper GroupViewModel / ConversationListViewModel flow remains the only path that creates groups.
Contributor
There was a problem hiding this comment.
Pull request overview
Guards MixinJob.createConversation against being called for GROUP conversations to prevent sending an invalid minimal POST /conversations request (missing random_id) that the server rejects, which was causing “invalid UUID”/missing-param errors when sending messages in non-SUCCESS local groups.
Changes:
- Add an early return in
MixinJob.createConversationfor group conversations. - Report the unexpected call path via
reportExceptioninstead of attempting the API create.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+185
to
+190
| if (conversation.isGroupConversation()) { | ||
| reportException( | ||
| "Skip MixinJob.createConversation for group", | ||
| IllegalStateException("conversation_id=${conversation.conversationId}"), | ||
| ) | ||
| return conversation.expireIn |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MixinJob.createConversationbuilds a minimalConversationRequestwith onlyconversationId,category, and a single-participant list — norandom_id,name, or full participants. That request shape is only valid for CONTACT (1v1) conversations, whoseconversationIdis deterministically derived from the two userIds.When a GROUP conversation falls into this path —
SendMessageJob.sendPlainMessage/sendEncryptedMessage/sendSignalMessagecallscheckConversationExist(conversation)for any non-SUCCESS local conversation regardless of category — the resultingPOST /conversationshits the server withcategory=GROUPbut norandom_id. The server rejects it as either "random_id missing" or "invalid UUID", which is what we've been seeing in error reports.Note that
MixinJob.checkConversation(the other entry) already short-circuits groups tojobSenderKey.syncConversation, so the bug only fires from the threeSendMessageJob.send*paths.This PR adds an explicit guard inside
createConversationitself: if the conversation is a group, report the unexpected state (so the issue surfaces if any future caller slips through) and returnconversation.expireInwithout hitting the API. Group creation is left to the proper flows that already supply a validrandomId:GroupViewModel.createGroupConversation(new group fromNewGroupFragment)ConversationListViewModel.createGroupConversation(retry fromConversationListFragmenton FAILURE state)Audit of all group-create paths
Verified every code path that can
POST /conversations:randomIdConversationJob.createGroup→conversationApi.createGroupViewModel.createGroupConversationUUID.randomUUID().toString()✓ConversationListViewModel.createGroupConversationUUID.randomUUID().toString()✓ConversationViewModel.createConversation→createSuspendCONTACTcategoryMixinJob.createConversation→conversationApi.createSendMessageJob.checkConversationExistOther
ConversationRequestconstructions (inSearchViewModel,BottomSheetViewModel,ContactViewModel, etc.) are all MUTE/UPDATE requests that hit/conversations/{id}/muteor/conversations/{id}and do not requirerandom_id.Test plan
POST /conversationsrequest is fired and no "invalid UUID" error in logsNewGroupFragmentstill works end-to-endConversationListViewModel.createGroupConversationstill drives recreation with a fresh randomIdreportExceptionif any unexpected caller hits the guard🤖 Generated with Claude Code