In short
... means "all the extra arguments this function was given". Only a function that lists ... in its own brackets has them. Luau found ... in a function that does not, most often an inner function written inside the one that does, such as the callback of task.delay, task.spawn or :Connect. Inner functions do not inherit the outer function's ....
What the message means
ServerScriptService.Logger:4: Cannot use '...' outside of a vararg function
It is a syntax error, so the script does not run at all. The line and column point at the ... that cannot be used there.
The main body of a script is allowed to use ...: in a ModuleScript or Script it is simply empty. The error only comes from inside a function that does not declare it.
Causes and fixes
Three things cause this error in practice. Each one below has the smallest code that triggers it, then the fix.
- ... used inside an inner function
- The function never lists ... in its brackets
- An event callback reads the outer arguments
... used inside an inner function
The outer function has ..., but the callback written inside it is a new function with its own, empty argument list.
local function logLater(...)
task.delay(1, function()
print("[log]", ...)
end)
end
logLater("Round", 3, "started")
Save the arguments in a table in the outer function with table.pack(...), and unpack them in the inner one. Or pass them on: task.delay(1, print, "[log]", ...).
local function logLater(...: any)
local args = table.pack(...)
task.delay(1, function()
print("[log]", table.unpack(args, 1, args.n))
end)
end
logLater("Round", 3, "started")
table.pack stores the count in n, so nil arguments in the middle are kept when you unpack with 1, args.n.
The function never lists ... in its brackets
Code copied from a function that took ... into one with named parameters, or a parameter list edited later, leaves ... with nothing to refer to.
local function announce(message)
-- announce has no ... in its brackets
print(message, select("#", ...), "extra values")
end
announce("Hello")
Add ... as the last parameter if the function should take extra arguments, or name every parameter instead.
local function announce(message: string, ...: any)
print(message, select("#", ...), "extra values")
end
announce("Hello", 1, 2)
An event callback reads the outer arguments
A RemoteEvent handler built inside a helper that takes ... cannot read those values from inside the handler.
local function bindLogger(remote, ...)
remote.OnServerEvent:Connect(function(player)
print(player.Name, ...)
end)
end
bindLogger(Instance.new("RemoteEvent"), "tag")
Pack the values first, or let the callback take its own ... if you meant the arguments the event passes.
local function bindLogger(remote: RemoteEvent, ...: any)
local tags = table.pack(...)
remote.OnServerEvent:Connect(function(player: Player, ...: any)
print(player.Name, table.unpack(tags, 1, tags.n), ...)
end)
end
bindLogger(Instance.new("RemoteEvent"), "tag")
Fix it in your place
Paste the error, RoCode fixes it in your place
Copy the line from Output and paste it here. RoCode opens the script it names in the place you have open in Studio, works out which of the causes above it is, and edits the code there instead of handing you a snippet to paste.
RoCode is an AI agent for Roblox Studio: it reads the scripts in the place you have open, finds the line and edits it there, and every change is an undo point. It runs on Windows or macOS with a desktop browser. Free to start, with free credits every day.
How to find the line that causes it
- A syntax error stops the whole script before its first line runs, so nothing in that script works, not just the broken line.
- Open the script. The Script Editor underlines the problem in red; hover over the underline to read the message.
- Open Script Analysis (View tab) to see every syntax error in every script, with its line number. Double-click one to jump to it.
- The line number in the message is where Luau gave up, which is often below the real mistake. The
(to close ... at line N)part points at the line where the unclosed bracket or block starts.
Questions
What does ... mean in Luau?
It stands for the extra arguments passed to a function that lists ... as its last parameter. You can pass it on, count it with select("#", ...) or store it with table.pack(...).
Why can my inner function not see ...?
Every function has its own .... Local variables from the outer function are visible inside, so copy the values into a local table first.
Can RoCode fix it?
Yes. Paste the Output line into RoCode. It reads the script in your open place and passes the values to the inner function correctly.
Sources and further reading
- Luau: syntax. functions and variadic arguments
- Roblox Creator Docs: functions. variadic functions
- Roblox Creator Docs: table library. table.pack and table.unpack
How the code was checked: every block marked Fixed passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 5 November 2026), and every block marked Breaks compiles only to fail with the message on this page. The message wording was checked by compiling each broken block on this page with luau-compile, which uses the same Luau parser as Roblox Studio, on 5 November 2026. A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.