TextChannel.OnIncomingMessage never gets called

Update: apparently it’s not never called, but the behavior is still weird. The content of this post remains accurate, but another post I made further down the thread provides more context. Still, read this first post before the follow-up ones.


Expected behavior

There are two OnIncomingMessage callbacks which should be usable:

That post is from before TextChatService became the default for new experiences earlier this year, and now the customization described in the quoted topic has documentation. It’s safe to assume that both of these callbacks should work now, but only TextChatService.OnIncomingMessage gets called.


Actual behavior

If the developer assigns a function to the callback TextChannel.OnIncomingMessage, the function is not called when a message gets sent in that text channel:

Code:

local textChatService = game:GetService("TextChatService")
local textChannels = textChatService:WaitForChild("TextChannels")
local generalTextChannel = textChannels:WaitForChild("RBXGeneral")

local callbackHolder = generalTextChannel

callbackHolder.OnIncomingMessage = function(textChatMessage)
	print(textChatMessage.Text, textChatMessage.TextChannel)
end

print("OnIncomingMessage callback connected for", callbackHolder)

If TextChannel.OnIncomingMessage was working as intended, the output would print Test RBXGeneral when I sent that message.

Changing the callbackHolder variable to textChatService in that code at least gives us a sign of life in the output when we chat, but this only reveals that the problem is with TextChannel.OnIncomingMessage and not anything in the code:

To reproduce the issue, paste the code excerpt into a client script placed in ReplicatedStorage, then type a chat message during a Play Solo session.


Important follow-up context (click the post):
2 Likes

Just following up on the OP here to pre-empt any questions about my code or suggestions about solutions I may not have tried — this post seems necessary but also didn’t feel appropriate including in the formal bug report.


For anyone reading, TextChatService.OnIncomingMessage firing twice in the output here is a Roblox thing — that’s got nothing to do with my code. It’s weird behavior, but it’s intended and is a side effect of the message replicating from the server back to the sending client. From the Creator Hub:

When bound to the client sending a message, this event can be fired twice, first when the message is initially sent and received locally by the same client, and then when the result of the filtered message is received by that client from the server.


Having my script manually send messages does not work to call TextChannel.OnIncomingMessage either. Appending the following code snippet to the bottom of the script from the OP does not solve our problem:

task.wait(2)
print("Sending scripted messages")
generalTextChannel:SendAsync("Scripted user message")
generalTextChannel:DisplaySystemMessage("Scripted system message")

Sidenote: if you noticed the order of the chat messages in that video is not the same as the order of the function calls in the code snippet, here is a post I wrote about that as well: Improve the TextChatService API so we can ensure messages appear in the correct order


According to this image from the In-Experience Text Chat Creator Hub page,


(you’ll have to zoom in, the resizing thing isn’t cooperating with me)

the TextChatService.OnIncomingMessage callback function is called first, and then TextChannel.OnIncomingMessage is called (presumably with the first callback function’s modified TextChatMessage fed into it, if applicable).

With this in mind, we have one last resort to try and make TextChannel.OnIncomingMessage work. If I change my script to have both callbacks bound, and the TextChatService.OnIncomingMessage function does a modification to the message just for good measure, then perhaps the TextChannel’s callback will be called?

local textChatService = game:GetService("TextChatService")
local textChannels = textChatService:WaitForChild("TextChannels")
local generalTextChannel = textChannels:WaitForChild("RBXGeneral")

textChatService.OnIncomingMessage = function(textChatMessage)
	print(0, textChatMessage.Text, textChatMessage.TextChannel)
	local new = Instance.new("TextChatMessageProperties")
	new.Text = textChatMessage.Text .. "!"
	new.PrefixText = textChatMessage.PrefixText
	return new
end

generalTextChannel.OnIncomingMessage = function(textChatMessage)
	print(1, textChatMessage.Text, textChatMessage.TextChannel)
end

print("OnIncomingMessage callbacks connected")

task.wait(2)
print("Sending scripted messages")
generalTextChannel:SendAsync("Scripted user message")
generalTextChannel:DisplaySystemMessage("Scripted system message")

It still does not get called. Note that no prints in the output begin with 1, which would signify that it works:

1 Like

Thanks for the report! We’ll follow up when we have an update for you.

1 Like

Big update:

I noticed that if TextChannel.OnIncomingMessage is assigned slightly after the session begins, it works. Putting a task.wait(1) at the top of the code from the OP,

task.wait(1)
local textChatService = game:GetService("TextChatService")
local textChannels = textChatService:WaitForChild("TextChannels")
local generalTextChannel = textChannels:WaitForChild("RBXGeneral")

local callbackHolder = generalTextChannel

callbackHolder.OnIncomingMessage = function(textChatMessage)
	print(textChatMessage.Text, textChatMessage.TextChannel)
end

print("OnIncomingMessage callback connected for", callbackHolder)

we can see that the callback does get assigned:

As a sidenote, you may also notice that my name text (the PrefixText) is no longer colored blue as it should be.

This seems like a bug as well, but I’m not sure. What I do know is that printing the PrefixText reveals no RichText color tag, even when using TextChatService.OnIncomingMessage which doesn’t have the discolored name problem that TextChannel.OnIncomingMessage does:

callbackHolder.OnIncomingMessage = function(textChatMessage)
	print(textChatMessage.PrefixText, textChatMessage.Text)
end

If it had a RichText tag, that output message would read:

<font color="#01a2ff">GFink:</font> hey

This would support the idea that Roblox assigns a RichtText color tag internally after OnIncomingMessage finishes executing — and that for some reason, the TextChannel version of OnIncomingMessage breaks this behavior.

Perhaps that’s a separate bug report, but I’ll worry about it another time.

Anyways — it appears the callback function is working in the above video only because it was assigned late. This would suggest that in the intervening 1 second we waited, something else happened to our TextChannel.OnIncomingMessage callback. Perhaps Roblox is internally overriding it with an empty function as soon as the chat window loads?

While we can’t print the raw callback property to see if the function got changed,

print(callbackHolder.OnIncomingMessage)

image

we can still test out our hypothesis by removing the task.wait(1) and then seeing if our TextChannel.OnIncomingMessage callback function gets executed during that very narrow slice of time before presumably getting overridden internally.

We’ll just use TextChannel::DisplaySystemMessage, since there’s no time to try and chat anything manually.

local textChatService = game:GetService("TextChatService")
local textChannels = textChatService:WaitForChild("TextChannels")
local generalTextChannel = textChannels:WaitForChild("RBXGeneral")

local i = 0
local s = i

generalTextChannel.OnIncomingMessage = function(textChatMessage)
	print(tostring(generalTextChannel) .. ":", textChatMessage.Text)
	s = tonumber(textChatMessage.Metadata)
end

print("begin")

while s == i do
	i += 1
	generalTextChannel:DisplaySystemMessage("test", tostring(i))
	task.wait()
end

local failMsg = "This message will display in the chat but not in the output"
generalTextChannel:DisplaySystemMessage(failMsg)

Testing this code, we see that TextChannel.OnIncomingMessage does indeed get called for a brief time until something overrides it:

You might have the impulse to complain about my code having a race condition, with my loop relying on the task.wait() line for there to be enough time for s to catch up to i.

However, even if that was a problem — and it’s not, because putting print(s) right after the DisplaySystemMessage line inside the loop reveals it’s always the same as i by that time if the OnIncomingMessage callback runsthe final line in the code should still result in a print to the output! It would look like this:

RBXGeneral: This message will display in the chat but not in the output

And it’s not there (as the string content suggests).

So that means something is causing my TextChannel.OnIncomingMessage assignment to become unbound. But this is the only client script I have in the whole game! The unbinding must be something internal.

1 Like

Hey thanks for the report. Looks like there’s two issues at play:

  • Its hard to determine if a callback is already assigned. (I’ve run into this issue a few times, this can be solved a few ways like assigning a readonly-boolean maybe)
  • The current corescripts overwrite any callbacks that happen to be assigned before they are ran

I will file this in my backlog and take look at these issues. In the meantime, the best I can offer is to assign your callbacks with a short delay like you’ve already discovered which is less than ideal

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.