UserHasBadgeAsync saying the user does not have the badge even though they do?

I have no idea if I am just being dumb or what, but my code here:

if plr and plr.Parent then
		local badgeservice = game:GetService("BadgeService")
		if plr.Badges:FindFirstChild(id) then else
			if game:GetService("BadgeService"):UserHasBadgeAsync(plr.UserId,id) then else

still runs after the UserHasBadgeAsync part EVEN though the player has the badge? What am I doing wrong??

Why are you putting else right after the conditional statement?

Not much else…

local model = Instance.new("Model",plr.Badges)
				model.Name = id
				badgeservice:AwardBadge(plr.UserId,id)
				local gemamount = game.ServerStorage.BadgeAwards:FindFirstChild(id)
				plr.leaderstats.Gems.Value = plr.leaderstats.Gems.Value + gemamount.Value
				require(game.ServerStorage.GameAnalytics):addResourceEvent(plr.UserId, {
					flowType = require(game.ServerStorage.GameAnalytics).EGAResourceFlowType.Source,
					currency = "Gems",
					amount = gemamount.Value,
					itemType = "Badge",
					itemId = id
				})
				local info = badgeservice:GetBadgeInfoAsync(id)
				game.ReplicatedStorage.SendNotif:FireClient(plr,info.IconImageId,"You have been awarded "..gemamount.Value.." gems for getting the badge "..info.Name.."")
				game.ReplicatedStorage.SendNotif:FireAllClients(info.IconImageId,plr.Name.." was awarded the badge "..info.Name.."")

The behavior you’re experiencing may be related to this unresolved issue. Are you seeing any errors in the output?

This has been happening for a few weeks before the post you linked was posted.

Looking at my error tracker there seems to a few errors poping up however they are from the last day so they dont have to do with this issue that I am experiencing I belive. However to fix this would I add a pcall? Plus is that error still going on?

I reward badges like this, if it helps:

local BadgeService = game:GetService("BadgeService")

function RewardBadge(Player, BadgeId)
	local BadgeID = BadgeId
	local playerID = Player.UserId
	local hasBadge = false
	local success, message = pcall(function()
		hasBadge = BadgeService:UserHasBadgeAsync(Player.UserId, BadgeID)
	end)
	if not success then
		warn("Server | Error while checking if player has badge: " .. tostring(message))
		return
	end
	if hasBadge == false then
		BadgeService:AwardBadge(Player.UserId, BadgeID)
	end
end
1 Like

It would be helpful if you could post the entire block of code that begins with:

if plr and plr.Parent then

I would also recommend adding more logs to that block of code so that you can see exactly which conditions are being met. It does seem unlikely that game:GetService("BadgeService"):UserHasBadgeAsync(plr.UserId,id) would evaluate to true if the player does not have the badge, even given Roblox’s service outage.

You shouldn’t seek to use pcall() as a means to fix errors, if that’s what you mean. pcall() should be used to handle errors that you know to expect and have a solution for. Using pcall() to simply hide errors can lead to further unexpected behavior. In the case of the Roblox issue I linked above, using pcall() would hide the error, but not fix the behavior of the part of the program that implements it, as Roblox’s service would still be throwing an error. You just wouldn’t see it.

I don’t see any response from Roblox telling us that it has been resolved, so I’d assume so.


By the way, not to get too off topic or nitpicky, but…

if plr.Badges:FindFirstChild(id) then else

This “if then else” approach for the first condition is a pretty unconventional and ill-advised coding pattern. Your code would be more readable if you simply used

if player.Badges:FindFirstChild(id) == false then

or even

if not plr.Badges:FindFirstChild(id) then

While the “if then else” pattern might look like it makes some sense in Lua, in just about any other language it would have to look like this:

if (plr.Badges:FindFirstChild(id)) {} else {}

which doesn’t really make any sense. It also makes it more difficult to later add a real “else” condition.

2 Likes

The reason I was gunna use pcalls is to check if the request was successful or not. If it was not successful then dont run the code.

Actually the other way around. The code still runs even though the player does have the badge. I want it to only run if the player does NOT have the badge.

Anyways here is the entire code.

local badgeservice = game:GetService("BadgeService")
game.ReplicatedStorage.AwardBadge.Event:Connect(function(plr,id)
	print(id)
	if plr and plr.Parent then
		if not plr.Badges:FindFirstChild(id) then
			local function checkbadge(plrid,id)
				return badgeservice:UserHasBadgeAsync(plr.UserId,id)
			end
			local success,data = pcall(checkbadge)
			if success == true and data == false then
				local model = Instance.new("Model",plr.Badges)
				model.Name = id
				badgeservice:AwardBadge(plr.UserId,id)
				local gemamount = game.ServerStorage.BadgeAwards:FindFirstChild(id)
				plr.leaderstats.Gems.Value = plr.leaderstats.Gems.Value + gemamount.Value
				require(game.ServerStorage.GameAnalytics):addResourceEvent(plr.UserId, {
					flowType = require(game.ServerStorage.GameAnalytics).EGAResourceFlowType.Source,
					currency = "Gems",
					amount = gemamount.Value,
					itemType = "Badge",
					itemId = id
				})
				local info = badgeservice:GetBadgeInfoAsync(id)
				game.ReplicatedStorage.SendNotif:FireClient(plr,info.IconImageId,"You have been awarded "..gemamount.Value.." gems for getting the badge "..info.Name.."")
				game.ReplicatedStorage.SendNotif:FireAllClients(info.IconImageId,plr.Name.." was awarded the badge "..info.Name.."")
				if id == 2124512616 then
					plr.Stats.CriticalChance.Value = plr.Stats.CriticalChance.Value - 1
				end
				if id == 2124512617 then
					plr.Stats.CriticalChance.Value = plr.Stats.CriticalChance.Value - 1
				end
				if id == 2124512665 then
					plr.Stats.CriticalChance.Value = plr.Stats.CriticalChance.Value - 1
				end
				if id == 2124512684 then
					plr.Stats.CriticalChance.Value = plr.Stats.CriticalChance.Value - 1
				end
				if id == 2124512965 then
					plr.Stats.CriticalChance.Value = plr.Stats.CriticalChance.Value - 1
				end
				if id == 2124512360 then
					plr.Stats.AttackCooldown.Value = plr.Stats.AttackCooldown.Value - 1
				end
				if id == 2124512361 then
					plr.Stats.AttackCooldown.Value = plr.Stats.AttackCooldown.Value - 1
				end
				if id == 2124512385 then
					plr.Stats.AttackCooldown.Value = plr.Stats.AttackCooldown.Value - 1
				end
				if id == 2124512488 then
					plr.Stats.AttackCooldown.Value = plr.Stats.AttackCooldown.Value - 2
				end
				if id == 2124512352 then
					plr.Stats.AttackDamage.Value = plr.Stats.AttackDamage.Value + 5
				end
				if id == 2124512353 then
					plr.Stats.AttackDamage.Value = plr.Stats.AttackDamage.Value + 5
				end
				if id == 2124512354 then
					plr.Stats.AttackDamage.Value = plr.Stats.AttackDamage.Value + 5
				end
				if id == 2124512356 then
					plr.Stats.AttackDamage.Value = plr.Stats.AttackDamage.Value + 5
				end
				if id == 2124512357 then
					plr.Stats.AttackDamage.Value = plr.Stats.AttackDamage.Value + 5
				end
				if id == 2124514868 then
					plr.Stats.Luck.Value = plr.Stats.Luck.Value + 5
				end
			end
		end
	end
end)

I assume you are trying to see if a player does “not” have a badge, then to run a function. But of course only after a Remote Event has been fired, because of you tried to use a :Connect function? The code below may solve your problem, if so:

Server code:

local BadgeService = game:GetService("BadgeService")
local Event = game.ReplicatedStorage:WaitForChild("AwardBadge") -- the remote event

local function YouNameThisFunction(player, id)
	local hasBadge = false
	if player and player.Parent then
		local BadgeID = id
		local playerID = player.UserId
		local hasBadge = false
		local success, message = pcall(function()
			hasBadge = BadgeService:UserHasBadgeAsync(playerID, BadgeID)
		end)
		if not success then
			warn("Server | Error while checking if player has badge: " .. tostring(message))
			return
		end
		if hasBadge == true then
			return warn(player.Name.. " already owns the badge, do nothing.")
		end
		if hasBadge == false then
			-- if player does not have Badge, then it runs the code below:
			print(player.Name.. "does not have the badge!")
		end
	end
end

Event.OnServerEvent:Connect(YouNameThisFunction)

Client code:

local Event = game.ReplicatedStorage:WaitForChild("AwardBadge") -- The remote event.
local Button = script.Parent.Parent.TextButton
local Player = game.Players.LocalPlayer

Button.MouseButton1Click:Connect(function() -- I used this to fire the event.
	local ID = 12345678 -- your BadgeId. If for some reason the badge is stored on the server, then only do Event:FireServer() and only get the player from the server function and not "id".
	Event:FireServer(ID)
end)