How to prevent warnings with :GetButton()

I keep getting this warning,
ContextActionService could not find the function passed in, doing nothing.
and having done prints, found that this is the line of code causing problems

if ContextActionService:GetButton('Sprint') then

According to the Developer Hub, it quotes

If no such action was bound or if a button was not created, this function returns nil .

And SO this if statement shouldn’t cause any problems, the code should not stop. As the ‘Sprint’ button is only created for those who have a gamepass, not everyone is gonna have it.

Also tried

if ContextActionService:GetButton('Sprint') ~= nil then

Also does not work

Can anyone explain why the code is stopping here?

GetButton() hub

1 Like

Don’t call GetButton for buttons that don’t exist. Keep track of whether or not this button actually exists externally, since you shouldn’t need to call code based on it unless they have it. Perhaps a variable called ‘hasSprintGamepass’ or similar?

Be wary of checking gamepasses on the client, as exploiters can change their user ID to manipulate some games into thinking they own all gamepasses. If this button triggers a remote event or function, make sure the server verifies the existence of their gamepass. If this button just changes your walk speed without asking the server, though, I guess there’s not much you can do. Exploiters are gonna exploit.

I do check server for gamepass ownership, and creating the button. However, I feel if the hub quotes that this function should return nil if the button doesn’t exist, then it should return nil and not error out.

1 Like

I wouldn’t rely on it to fail silently if the button doesn’t exist. Better to just not execute the code unless you actually have the pass, since exploiters can simply create a button called ‘Sprint’ and suddenly your check has been cracked.

Do all your ‘has gamepass’ checks as early as possible and don’t perform them again. This will give exploiters less time to manipulate the checks. Distribute these variables to any script that needs them. After the game has loaded, anything is fair game for an exploiter to modify. It can take a few seconds after the game has started for an exploiter to start up their scripts, even if they’re fast.

1 Like

It appears that GetButton yields the thread, instead of returning nil. (Notice how it has a yields tag?)

local ContextActionService = game:GetService"ContextActionService"
local thread = coroutine.create(function()
	print(ContextActionService:GetButton'aaa')
end)
coroutine.resume(thread) -- emits warning
print(coroutine.status(thread)) --> suspended
coroutine.resume(thread,1,2,3) --> 1 2 3
print(coroutine.status(thread)) --> dead

The documentation is wrong in this case, it doesn’t return nil, it yields.

1 Like

I do checks everytime they try to sprint

local function InputBegan(input, GPE)
	if GPE or not CheckGamepass:InvokeServer(Player, 'Running Shoes') or Humanoid.WalkSpeed == 0 then return end
	
	if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.ButtonR2 then
		Humanoid.WalkSpeed = 26
		Sprinting = true
		
		CameraManipulation.StartSprint(Sprinting)
	end
end

local function InputEnded(input, GPE)
	if GPE or not CheckGamepass:InvokeServer(Player, 'Running Shoes') or Humanoid.WalkSpeed == 0 then  return end

	if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.ButtonR2 then
		Humanoid.WalkSpeed = 18
		Sprinting = false
		
		CameraManipulation.StartSprint(Sprinting)
	end
end

As 1. If I just used a variable, couldn’t they just change the variable to true? And 2. If they buy the gamepass mid game I’d have to do some messy ProcessReceipt junk and fire back to client stuff.

You are messaging the server and, more importantly, waiting for a response, on every input begin and end. This is a very bad idea. I would recommend doing this once on load, and storing the result in a local variable. Tell someone to rejoin a server if they buy a game pass - like most games on roblox do.

Exploits can modify local variables but it’s much much more complicated and messy and it breaks every time your game updates. This is ideally what you want.

I’ve had players leave dislikes on my games because they have to leave and rejoin if they buy a gamepass during the game. I’d want it to be instant, purchase item, you get the perks immediately

Then, have the purchase be in-game. Bring up a prompt, then after they close the dialog, check with the server once to see if they have the pass now, and if they do, update the local variable and call your function to add the perk buttons/GUIs. Should work just fine, and make exploiting difficult.