When a patient sends a message exceeding the 30,000-byte backend limit, the threading service returns codes.InvalidArgument. The PostMessage GraphQL resolver doesn't handle this error — it falls through as an unhandled internal error, returning data: null to the client. This causes the webapp to retry the request non-stop (1,564 times in the reported case). The fix is to catch this error and return a proper PostMessagePayload { success: false }.
File: backend/cmd/svc/baymaxgraphql/internal/schema/baymaxgraphql.graphql (line 1113-1114)
Add a new enum value to PostMessageErrorCode:
"The message text exceeds the maximum allowed length."
MESSAGE_TOO_LONG
cd backend && go generate ./cmd/svc/baymaxgraphql/internal/schemaThis generates the Go constant PostMessageErrorCodeMessageTooLong in baymaxgraphql.graphql.go.
File: backend/cmd/svc/baymaxgraphql/internal/resolvers/mutation_post_message.go (lines 108-126)
After the existing invalidAttachmentError and ErrorCodeReadOnly checks, add a check for codes.InvalidArgument:
if errors.GRPCStatusCode(err) == codes.InvalidArgument {
return &schema.PostMessagePayload{
Success: false,
ErrorCode: schema.PostMessageErrorCodeMessageTooLong,
ErrorMessage: "Message is too long.",
}, nil
}This goes before the final return nil, errors.Trace(err) at line 125. It follows the exact same pattern as the ErrorCodeReadOnly check above it.
Note: codes.InvalidArgument from r.postMessage() could theoretically come from other RPCs called inside that function (e.g., transformRequestToMessagePost, determineOutboundEndpoints). However, examining those code paths, they don't return InvalidArgument — and even if they did, returning MESSAGE_TOO_LONG for any InvalidArgument from the post-message flow is a reasonable user-facing response. The alternative (checking the error message string) would be brittle.
File: backend/cmd/svc/baymaxgraphql/internal/resolvers/mutation_post_message_test.go
Add a new test TestPostMessage_MessageTooLong that:
- Sets up the standard test models and context (same as existing tests)
- Mocks
Thread()to return a valid thread - Mocks
CanPostMessage()to succeed - Mocks
DevicesForIDs()to succeed - Mocks
PostMessage()to returnstatus.Errorf(codes.InvalidArgument, "Message text is 55659 bytes which is longer than max allowed of 30000") - Sends the mutation and asserts the response is
{ "data": { "postMessage": { "success": false, "errorCode": "MESSAGE_TOO_LONG", "errorMessage": "Message is too long." } } }
This test is simple because most of the setup is the same as existing tests — it just changes the mock return value for PostMessage().
goimports -w backend/cmd/svc/baymaxgraphql/internal/resolvers/mutation_post_message.go
goimports -w backend/cmd/svc/baymaxgraphql/internal/resolvers/mutation_post_message_test.go
cd backend && ./runlint.sh ./cmd/svc/baymaxgraphql/...cd backend && go test -run TestPostMessage_MessageTooLong ./cmd/svc/baymaxgraphql/internal/resolvers/- Unit test passes with correct
success: false,errorCode: MESSAGE_TOO_LONG,errorMessageresponse - Lint passes
- Existing PostMessage tests still pass
- Optional: re-test in dev Chrome to confirm the webapp no longer retries (it should show the error toast and stop)
backend/cmd/svc/baymaxgraphql/internal/schema/baymaxgraphql.graphql— add enum valuebackend/cmd/svc/baymaxgraphql/internal/schema/baymaxgraphql.graphql.go— regeneratedbackend/cmd/svc/baymaxgraphql/internal/resolvers/mutation_post_message.go— add error handlingbackend/cmd/svc/baymaxgraphql/internal/resolvers/mutation_post_message_test.go— add test