Why does processReceipt not run when I do a purchase on studio?

I am trying to make a currency and have another issue, my script seems to not detect when a purchase is done, and my processReceipt function runs when the game starts. Here is my script:

local function processReceipt(info)
	print("smelly oompa loompa body")
	local plrProductKey = info.PlayerId .. "_" .. info.PurchaseId -- Here is where my error occurs, attempt to index a nil value.
	local purchased = false
	local suc, errormsg = pcall(function()
		purchased = purchaseHistory:GetAsync(plrProductKey)
	end)

Can someone help me out with this? In-game currency is extremely difficult. I am also using datastore2 (Roblox/DataStore2.module.lua at master · Kampfkarren/Roblox · GitHub) if that helps. I tried using it originally, and tried again with the regular ROBLOX datastore with the same error.

1 Like

Can you show how you’re using the function?

1 Like

After processReceipt is done being defined, the function is run using this code:

Server.MarketplaceService.ProcessReceipt = processReceipt()

(Server.MarketplaceService is just a variable for MarketplaceService)

You should not be using it like that. Your callback connection method should look like this:

MarketplaceService.ProcessReceipt = processReceipt

When you put the parentheses, the function never receives the info parameter.

This is because nothing is calling it,also datastore2 uses player objects to save, not keys.To call the function do, marketplaceservice.OnProductPurchase:Connect(processReceipt) or however you wanna call it.

Okay, I fixed it using PromptPurchaseFinished. Now, I get no output.

local function processReceipt(Player,asset,tPur)
	if tPur then
	print("smelly oompa loompa body")
	local plrProductKey = Player.UserId .. "_" .. asset -- Here is where my error occurs, attempt to index a nil value.
	local purchased = false
	local suc, errormsg = pcall(function()
		purchased = purchaseHistory:GetAsync(plrProductKey)
	end)

This should be making it run. Do purchases count on studio?

Server.MarketplaceService.PromptPurchaseFinished:Connect(processReceipt)

Oh sorry, You would call it with MarketplaceService.ProcessReceipt:Connect(processReceipt)

That’s incorrect. ProcessReceipt requires a callback function, it’s not an Event.


@stalecars: Please look back on the solution I posted above. That's how you should be connecting the event.

Okay, the function finally runs when it should. I now have an issue with:

local function processReceipt(receiptInfo)
	print("smelly oompa loompa body")
	local plrProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId -- Here is where my error occurs, attempt to index a nil value.
	local purchased = false
	local success, errorMessage = pcall(function()
		purchased = purchaseHistory:GetAsync(plrProductKey)
	end)
	if success and purchased then
		return Enum.ProductPurchaseDecision.PurchaseGranted
	else
		error("[SERVER] Data Store Error! Details: " .. errorMessage) -- Server:215: attempt to concatenate a nil value

What is purchaseHistory defined as? Is the error you gave on line 3 still there? Does the error on line 215 start with "[SERVER] Data Store Error! Details: "? Keep in mind that success can be true (which means errorMessage is nil) but purchased can still be a falsey value.

Purchasehistory is a data store which I used datastoreservice:getdatastore for. No errors for that.

and no, I do not have the original error. Just the new error.

The problem in short from what I see is that purchaseHistory:GetAsync(plrProductKey) is blank. There’s nothing there as we can see, therefore, it’s a falsey value. If it’s a falsey value, it does not meet the first condition in your if-statement (that success is true and purchased is a truthy value). You’re going to need a value there in the first place if you need PurchaseGranted. From my perspective, I don’t think you’re looking to not GetAsync the purchaseHistory but rather SetAsync so something like this would work:

...
	local success, errorMessage = pcall(function()
		purchaseHistory:SetAsync(plrProductKey, true)
	end)
	if success then
		return Enum.ProductPurchaseDecision.PurchaseGranted
    else
...

I’m dumb, I meant to set the record of the player purchasing the item. It works completely now, except now my function (to give the player what they purchased) does not run.

local handler = productFunc[receiptInfo.ProductId]
	
	local success, result = pcall(handler, receiptInfo, Player)
	if not success or not result then
		warn("[SERVER] Error occurred while processing a product purchase.")
		print("\nProductId:", receiptInfo.ProductId)
		print("\nPlayer:", Player)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

Below is my function to give the player their money

productFunc[617923600] = function(receipt, plr)
	print("fat") -- does not output
	local val = 500
	local PlayerStoredData = Server.DataStoreService("Money", plr)
	local CURPLRDTA = Server.PlayerData:FindFirstChild(plr.Name)
	local MNEYDATA = CURPLRDTA:FindFirstChild("Money")
	if MNEYDATA then
		MNEYDATA.Value = MNEYDATA.Value + val
		sendNumberPlayerData(plr, MNEYDATA.Value) -- a function to refresh the players gui balance
		PlayerStoredData:Increment(val) -- datastore2 increment
		return true
	end
end

I think my pcall() is the reason that it does not work, but I am not sure.

Where is that chunk of code placed in relation to your other code? What’s Player defined as? Could you try giving a bigger piece of code so we can see how all this fits together?

sorry for the vagueness, just trying to make sure that in the future my game won’t be exploited/manipulated, but the chunk that gives the player their money that they purchased is located right above the function. Let me try to make it easier to read:

productFunc[617923600] = function(receipt, plr)
	print("fat") -- does not output
	local val = 500
	local PlayerStoredData = Server.DataStoreService("Money", plr)
	local CURPLRDTA = Server.PlayerData:FindFirstChild(plr.Name)
	local MNEYDATA = CURPLRDTA:FindFirstChild("Money")
	if MNEYDATA then
		MNEYDATA.Value = MNEYDATA.Value + val
		sendNumberPlayerData(plr, MNEYDATA.Value) -- a function to refresh the players gui balance
		PlayerStoredData:Increment(val) -- datastore2 increment
		return true
	end
end
local purchaseHistory = game:GetService("DataStoreService"):GetDataStore("Purchased")
local function processReceipt(receiptInfo)
	print("smelly oompa loompa body")
	local plrProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId -- Here is where my error occurs, attempt to index a nil value.
	local purchased = false
	local success, errorMessage = pcall(function()
		purchaseHistory:SetAsync(plrProductKey, true)
	end)
	if success then
		return Enum.ProductPurchaseDecision.PurchaseGranted
	else
		error("[SERVER] Data Store Error! Details: " .. errorMessage)
	end
	local Player = Server.Players:GetPlayerByUserId(receiptInfo.PlayerId)
	if not Player then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	local handler = productFunc[receiptInfo.ProductId]
	
	local success, result = pcall(handler, receiptInfo, Player)
	if not success or not result then
		warn("[SERVER] Error occurred while processing a product purchase.")
		print("\nProductId:", receiptInfo.ProductId)
		print("\nPlayer:", Player)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	local success, errorMessage = pcall(function()
		purchaseHistory:GetAsync(plrProductKey, true)
	end)

Here’s the issue, you’re returning something inside your function. When you return something inside a function, the code that follows is never executed. You should change the chunk that returns PurchasedGranted to this and make the SetAsync value to false before you give the item.

	if not success then
		error("[SERVER] Data Store Error! Details: " .. errorMessage)
	end

At the very end (after giving the item), you should SetAsync the purchase to true. You should only return PurchaseGranted at the very very end of your ProcessReceipt callback function.

1 Like

Okay, fixed it.

local function processReceipt(receiptInfo)
	print("smelly oompa loompa body")
	local plrProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId -- Here is where my error occurs, attempt to index a nil value.
	local purchased = false
	local success, errorMessage = pcall(function()
		purchaseHistory:GetAsync(plrProductKey, true)
	end)
	if success then
		return Enum.ProductPurchaseDecision.PurchaseGranted
	else
		error("[SERVER] Data Store Error! Details: " .. errorMessage)
	end
	local Player = Server.Players:GetPlayerByUserId(receiptInfo.PlayerId)
	if not Player then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	local handler = productFunc[receiptInfo.ProductId]
	
	purchaseHistory:SetAsync(plrProductKey, false)
	
	local success, result = pcall(handler, receiptInfo, Player)
	if not success or not result then
		warn("[SERVER] Error occurred while processing a product purchase.")
		print("\nProductId:", receiptInfo.ProductId)
		print("\nPlayer:", Player)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	local success, errorMessage = pcall(function()
		purchaseHistory:SetAsync(plrProductKey, true)
	end)
	if not success then
		error("[SERVER] Cannot save purchase data! Details: " .. errorMessage)
	end
	return Enum.ProductPurchaseDecision.PurchaseGranted
	end

I still don’t have the handler function run, however

You haven’t fixed it, that’s still the same code as you’re returning purchase granted 9 lines in. Please re-read my answer above and follow all the steps outlined in there.

1 Like

Oops, I thought you meant at the end. completely forgot about the beginning:

local purchaseHistory = game:GetService("DataStoreService"):GetDataStore("Purchased")
local function processReceipt(receiptInfo)
	print("smelly oompa loompa body")
	local plrProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId -- Here is where my error occurs, attempt to index a nil value.
	local purchased = false
	local success, errorMessage = pcall(function()
		purchaseHistory:GetAsync(plrProductKey, true)
	end)
	if success then
		purchaseHistory:SetAsync(plrProductKey, false)
	else
		error("[SERVER] Data Store Error! Details: " .. errorMessage)
	end
	local Player = Server.Players:GetPlayerByUserId(receiptInfo.PlayerId)
	if not Player then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	local handler = productFunc[receiptInfo.ProductId]
	

	
	local success, result = pcall(handler, receiptInfo, Player)
	if not success or not result then
		warn("[SERVER] Error occurred while processing a product purchase.")
		print("\nProductId:", receiptInfo.ProductId)
		print("\nPlayer:", Player)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	local success, errorMessage = pcall(function()
		purchaseHistory:SetAsync(plrProductKey, true)
	end)
	if not success then
		error("[SERVER] Cannot save purchase data! Details: " .. errorMessage)
	end
	return Enum.ProductPurchaseDecision.PurchaseGranted
	end

edit: It worked! Thank you so much