Reproduction Steps
There’s an issue in Roblox’s ChatServiceRunner script where an unhandled error can occur due to a GetChatForUserAsync call which is not wrapped in a pcall. This ends up causing the client’s chat box to be completely broken and nonfunctional.
In the script ChatServiceRunner.ChatChannel, there is a method called GetHistoryLogForSpeaker
which calls filterResult:GetChatForUserAsync(player.UserId)
without wrapping it in a pcall. As noted in the documentation, that function will throw an error if the two users cannot chat:
function methods:GetHistoryLogForSpeaker(speaker)
local userId = -1
local player = speaker:GetPlayer()
if player then
userId = player.UserId
end
local chatlog = {}
for i = 1, #self.ChatHistory do
local logUserId = self.ChatHistory[i].SpeakerUserId
if self:CanCommunicateByUserId(userId, logUserId) then
local messageObj = ShallowCopy(self.ChatHistory[i])
--// Since we're using the new filter API, we need to convert the stored filter result
--// into an actual string message to send to players for their chat history.
--// System messages aren't filtered the same way, so they just have a regular
--// text value in the Message field.
if (messageObj.MessageType == ChatConstants.MessageTypeDefault or messageObj.MessageType == ChatConstants.MessageTypeMeCommand) then
local filterResult = messageObj.FilterResult
if (messageObj.IsFilterResult) then
if (player) then
messageObj.Message = filterResult:GetChatForUserAsync(player.UserId)
else
messageObj.Message = filterResult:GetNonChatStringForBroadcastAsync()
end
else
messageObj.Message = filterResult
end
end
table.insert(chatlog, messageObj)
end
end
return chatlog
end
While the GetHistoryLogForSpeaker function tries to check if the users can chat earlier in the loop, that check doesn’t appear to be working perfectly, as I’m still recording errors that occur with the GetChatForUserAsync
call.
GetHistoryLogForSpeaker is called when the GetInitDataRequest RemoteFunction is invoked by clients who have just joined the game and are trying to load the initial chat logs. If this function errors, then the client’s chat script will completely fail to load, and the chat box and chat bar will be broken.
While I don’t have accounts available to test the exact conditions this occurs under, it is presumably due to some combination of players who have different chat settings which may be triggering an edge case when joining the game and trying to load the other person’s messages. Regardless of the cause, the GetChatForUserAsync
should always be wrapped in a pcall as specified in the documentation, and it should have proper error handling.
Expected Behavior
The error which can occur when calling GetChatForUserAsync
should be properly handled and should not cause the chat scripts to break.
Actual Behavior
When the issue occurs, the following errors are recorded:
Server:
Client:
The chat box is then completely broken for the client which tried to load that data. Screenshot from a player who reported the issue:
I’ve recorded hundreds of occurrences of this error in my analytics, and multiple players have reported this issue.
Workaround
Current workaround is to just fork the ChatServiceRunner script and manually add error handling to the function.
Issue Area: Engine
Issue Type: Other
Impact: Moderate
Frequency: Sometimes