ContextActionService:GetButton never returns if button doesn't exist

ContextActionService:GetButton(actionName) according to the Roblox wiki:

However, when I call it with an actionName that hasn’t been bound at all yet, instead of returning nil, the function quite literally never returns.

This has been causing issues in my game for a few weeks and I finally traced it back to this.

I have adjusted my game to work in spite of this quirk, but I figured it would be best to have it fixed anyway.

12 Likes

That explains why it’s a YieldFunction at least…

1 Like

This still happens. I also assumed what was written on the Developer Hub would be correct, but I ran in to this issue when testing on PC. This gave me a headache while undoing recent changes until I diagnosed this as the problem.

On mobile it was working fine, but I don’t know of any way of finding if the button will exist or not - I guess I could rely on a timeout, but that’s not a sufficient solution. This method would preferably act as it says on the Developer hub, or give us a method to detect whether or not the button exists. It seems odd that it will hang indefinitely without warning, I hope this is not intended behaviour and incorrect documentation.

3 Likes

Sanity check the actionName that you want to do a ContextActionService:GetButton() on prior with
ContextActionService:GetBoundActionInfo() ie. It’s not nil, has non-nil inputTypes
For completeness, you should check for the existence of TouchGui.TouchControlFrame prior as well
(an exercise for the reader.)

1 Like

This still wouldn’t work, even if I sanity check. On PC, there isn’t a button so it will yield indefinitely.

Your suggestion to check for the TouchGui.TouchControlFrame is what I was already doing, but this is still not a sufficient solution as it isn’t at all future proof. The GUI could be renamed or removed entirely at any point in a future update.

1 Like

You say you’re already doing it, so you know it does work.
(Don’t call GetButton() if no TouchControlFrame in use.)
Nothing is future-proof. But it’s what you can use until they fix this bug.

1 Like

While this is technically true, you can assume that API methods will be supported for the forseeable future - even if their behaviour changes, it’d be extremely unlikely that the behaviour would break usage of it.

Although the work-around will suffice for now, it can’t be relied upon (whereas API methods can). People will use this work-around and forget about the fact that a future update could easily break it, this bug being fixed could prevent that - which is the whole reason I bumped this old thread.

1 Like

Behavior changing breakage happens all the time in the real world. Yes, of course in an ideal world you
try to stick to defined APIs, and avoid internals, but after all, this is the Engine Bugs category, where new
Engine Bugs crop up all the time so people need to come up with workarounds in the interim which
means their code has already been broken, forcing them to change their code; just the same as if they
were using not-guaranteed-to-be-stable internals and something changed.
As someone who has been
programming for decades, I can tell you that this is more true today than ever–In the past it wasn’t so
easy to push out a software update at the drop of a hat. So nowadays if someone breaks an API for you,
the attitude is “well we can just push out a fix” and “the users of the API can push out their workarounds to
our breakage anyway.” BTW, I appreciate you bumping this thread even if others don’t. :slight_smile:

1 Like

I just had exactly the same experience as @General_Scripter did and would like to bump this thread for Engineer’s attention.

and If anyone else is having the same issue you can use this UserInputService.TouchEnabled


4 Likes

This is still an issue, been scratching my head trying to figure this out until I realized what was going on. Easy to reproduce:

local cas = game:GetService('ContextActionService')
cas:BindAction('TestAction', print, true, Enum.KeyCode.E)

print('before')
local button = cas:GetButton('TestAction')
print('after')

If you test this on any interface that would create a button, “before” and “after” are printed. Otherwise, GetButton yields infinitely.

6 Likes

I think I found a way to see if the button gui exists:

if PlayerGui:FindFirstChild("ContextActionGui") then
local button = ContextActionService:GetButton("Button")
button .Size = UDim2.new(0.3, 0, 0.35, 0) -- i just needed to size but only if the player on mobile
end
1 Like

This is still occurring today. Was wondering why my BindToRenderStep wasn’t running the function below it, and it turns out that since I’m calling this function on a touchless device, it yields indefinitely. I expect the behavior of this to try and get the button, and if it doesn’t exist, return nil.

Even a wiki page states that it can return nil, but it can never return anything other than the button, if touch controls are present. If this is somehow intentional, clearer documentation would be useful.

2 Likes

Just experienced the same thing. ContextActionService:GetButton hangs up forever instead of returning nil as the wiki says.

1 Like

Bumping this as the bug is still present and it made me resort to spamming prints all over an 8k line script for an hour or so till i could pin it down to this exact thing.

3 Likes

This issue makes me want to outright avoid using this. It’s simply too hazardous. At the very least this should show a warning after a few seconds so it can be nailed down when it hangs your code.

3 Likes

Just ran into this again, forgetting I ran into it in February. GetButton still yields forever, not leaving any sign that it cannot find the button.

Hi all!

I just released a fix for this. Please let me know if this resolves the issue or if any additional problems occur!

Thanks!

4 Likes

I’m getting a nil error with :GetButton that I haven’t had happen before, I haven’t edited this script and just found this comment so I’m just guessing the update might have something to do with it

ContextActionService:BindAction("TauntMenu", function(name, state, input)
	if state == Enum.UserInputState.Begin then
		if script.Parent.Enabled == false then
			script.Parent.Enabled = true
		else
			script.Parent.Enabled = false
		end
	end
	return Enum.ContextActionResult.Pass
end, true, TauntKey, Enum.KeyCode.ButtonR2)
ContextActionService:SetPosition("TauntMenu",UDim2.new(.65,0,0,0))
ContextActionService:GetButton("TauntMenu").Size = UDim2.new(0.35,0,0.35,0)
ContextActionService:SetTitle("TauntMenu", "🔊")
1 Like

Hi! If you’re testing on a non touch device, a button is never created and GetButton will return nil, like mentioned in the documentation here. Please check if the button exists before trying to change the size or checking if the device is a touch device.

Please note that on any non touch device SetTitle would not have been called as GetButton would hang silently. The behavior is the same, you’re now just correctly seeing the error.

Thanks

1 Like

Apologies, this is the reason I was getting the error! Thanks for the reply

2 Likes