ProcessReceipt automatically marks receipts as resolved if the callback is not connected

This bug report was written on behalf of @robloxandtyler

Expected behavior

I expect for ProcessReceipt callback of MarketplaceService to not mark the receipt as resolved if the callback is not yet connected, and to continue retrying each time the player rejoins the game until it is resolved by returning Enum.ProductPurchaseDecision.PurchaseGranted.

Current behavior

The issue is that if the callback is not connected, it will automatically mark it as successful and stop retrying. This can cause receipts to unexpectedly fail and not retry if the script yields or errors before setting the callback. This behavior is unexpected and not mentioned in the documentation.

The following is a description from another developer (@robloxandtyler) of a scenario where this caused many unresolved receipts to be lost: “My game uses InsertService to insert an important module, which my receipt processing script has to wait for. I ended up believing that my code for receipts would retry failed ones properly, because it worked when I had tested it. In reality, it had a random chance to fail to resolve the receipt and to stop retrying. This happened in scenarios where inserting that important module took too long and ProcessReceipt wasn’t connected before it was called.”

Reproduction steps

Attached below is an example place file where the issue can be reproduced.
Bug Example.rbxl (59.5 KB)
Publish the place, add a DevProduct, and insert the product ID in the local script located inside the purchase UI. In the live game, purchase the product and rejoin. Because the ProcessReceipt callback wasn’t connected before the player joined, it will stop retrying even after removing the wait and rejoining again.

2 Likes

Thank you for the report. We have assigned to our team for further review.