Chat scripts breaking due to lack of error handling for GetChatForUserAsync call

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:
error2

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

10 Likes

Got a lot of users from my game reporting about this recently, would appreciate if this was fixed.

I believe this is related:

Thanks for the report. We are invastigating.

1 Like