Pcall(), xpcall() and ypcall() Tutorial - How do they work?

Welcome curious Developers!

In this tutorial, I’ll be explaining how pcall() and xpcall() functions work and what happened to ypcall().

Let’s start


pcall() is short for P rotected Call , if the code inside of this function has an error it will yield until the attached function run without any issues and won’t stop the rest of the script. It also returns two values: A bool one and a variant one.

local boolValue, variantValue = pcall(function() -- 1
    -- this code is protected
  1. Naming the bool and the variant value, attaching pcall() to anonymous function.

The bool value is true when the function attached to pcall() ran without any issues, otherwise, it’s false; the variant value is a bit more complicated but let me explain as well as I can. When the bool value is false (error in the code), the variant value will contain the error that can be displayed with orange text in output using warn() function.

local boolValue, variantValue = pcall(function()
    -- this code is protected
    return 'hi' -- 1

if boolValue == false then -- 2
    warn(variantValue) -- 3
    print(variantValue) -- 4
  1. Explained below
  2. Checking if there was an issue in the script.
  3. This function will be executed when bool is false
  4. This function will be executed when bool is true

warn() is like print() but print() writes information in the output and warn() writes warning which have orange text color.

But what will happen when the code inside the function doesn’t have any issues? If you don’t use return procedure the variant variable will return nil. You can use the return function if you want to store data from the script into the universal variable.

local successed, errData = pcall(function()
    return "string" -- 1


-- Output:
-- 1
-- 2
-- 3
-- 'string'
  1. You can too return other values.

Use of pcall()

The most popular use of pcall() is data storing because functions like GetAsync() or SetAsync() are network calls and they can generate an error. pcall() is the best option in this case.


It’s better than pcall() (at least for me) because you can customize the error handler and it’s not yielding , if you know Python you can compare it to try-except block but xpcall is more universal. You have to provide 2 functions and if the first one “fail” the second one will run.

local successed, returnedData = xpcall(function()
    -- protected code
end, function() -- 1
    print('there is an error')
  1. This function will run when the previous function got an error, simple right?


Short for “Yielding Protected Call”. Sometime pcall() wasn’t yielding and then ypcall() was useful but now pcall() is yielding too and this is the same thing so ypcall() is just deprecated and you should not use it anymore.

The End

I recommend reading Lua Globals because there is a short description for some functions and variables (for pcall() and xpcall() too), the rest is in Roblox Globals. That was my first community tutorial in DevForum, hope it’s understandable because English isn’t my strong point. I’d be happy if you give your opinion.

Thanks for reading , have a nice day! :smiley:


Except that wouldn’t create an error because calling a function like that is valid syntactically. It is the equivalent of this: print({'hi'})


ypcall global still exist in Luau but it’s deprecated as now pcall actually yields the code when called. In fact, both ypcall and pcall literally point to the same function.


How does this tutorial differ from this other one? ReturnedTrue’s tutorial seems to go more in depth and even explains when using the functions would be more preferable.

This is incorrect, types are not first class therefore cannot be returned by functions, passed around as arguments, etc. I believe you meant you can return any value of any datatype.


Is it me or is anyone experiencing this issue? When you call that function with pcall, roblox studio seems to error and crash. I can’t seem to find a way to use that line without studio crashing

1 Like

@BenMactavsin, @incapaz and @BuildingRobloxUnited thanks for support. I updated the tutorial so hope it’s now correct.

not sure if you care, but the title has bad grammar

you said “How they works”

Thanks for report, “How they work” is fine?


since it is a question
“How do they work?”
would fit better

1 Like

I think it’s best practice to use pcall and ignore xpcall, but that’s just my opinion.
I’ve tried a few benchmarks to try it out:
pcall would be relatively a bit faster when there are no errors occurring.
pcall would be relatively a little bit faster when there are errors occurring.
(The functions are empty, otherwise the results won’t be clear)

local osclock,pcall,xpcall,print,error=os.clock,pcall,xpcall,print,error
local Table={}
function Table:Example(Value)end
function Table:ErrorExample(Value)return error()end
local function ErrorPrintFunction(ErrorMessage)end

local function BenchMark_pcall(Name, Function)
	local Start	=	osclock()
	for a=1,100000 do
		local Success, Result	=	pcall(
		if not Success then
	print(Name .. osclock() - Start)
local function BenchMark_xpcall(Name, Function)
	local Start	=	osclock()
	for a=1,100000 do
	print(Name .. osclock() - Start)

BenchMark_pcall("pcall without error  ", Table.Example)
BenchMark_xpcall("xpcall without error ", Table.Example)
BenchMark_pcall("pcall with error     ", Table.ErrorExample)
BenchMark_xpcall("xpcall with error    ", Table.ErrorExample)


I’ve tried it multiple times and results are about the same.

However, this is just a tiny bit of time over a frequent amount and it wouldn’t do any harm to use xpcall instead of pcall in most cases. (Just keep in mind to not use ypcall, it’s deprecated)

If the functions contain some code, the difference would barely be visible. Though I’d go for the fastest one personally.