Roblox Studio syntax error

Expected 'end' (to close 'function' at line 1), got <eof>

What Expected 'end' (to close 'function' at line 1), got <eof> means in Roblox Studio, the three things that cause it with the code that triggers each, and the fix for each one.

Updated 23 October 20263 min readSyntax errorLuau

In short

Every function, if ... then, for ... do and while ... do needs its own end. This message says one of them is missing one. The part in brackets tells you which block and where it starts: (to close 'function' at line 3). Luau also adds did you forget to close 'then' at line N? when it can tell an inner if is the real culprit.

  • Count: each function, then (of an if) and do opens a block; each end closes the newest open one. elseif and else do not need their own end.
  • Indenting each block one step makes a missing end easy to see.
On this page
  1. What it means
  2. Causes and fixes
  3. Fix it with RoCode
  4. Find the line
  5. Questions
  6. Sources

What the message means

Output (example)
ServerScriptService.Shop:12: Expected 'end' (to close 'function' at line 3), got <eof>

Other forms of the same message:

  • Expected 'end' (to close 'then' at line 4), got <eof>
  • Expected 'end' (to close 'do' at line 2), got <eof>
  • Expected 'end' (to close 'function' at line 1), got <eof>; did you forget to close 'then' at line 2?

Luau reads to the end of the script (got <eof>) and finds a block still open. Because end always closes the newest block, a missing end deep inside often shows up as the outer function being unclosed. That is why Luau adds the did you forget to close hint.

Like every syntax error, it stops the whole script: no line of it runs until it is fixed.

Causes and fixes

Three things cause this error in practice. Each one below has the smallest code that triggers it, then the fix.

An if inside a function has no end

The inner if takes the function's end as its own, so the function is left open.

Breaks Script in ServerScriptService named Coins
local function onTouched(hit)
	if hit.Name == "Coin" then
		print("coin!")
end

Add the end for the if, at the indentation of the if.

Fixed Script in ServerScriptService named Coins
local function onTouched(hit: BasePart)
	if hit.Name == "Coin" then
		print("coin!")
	end
end

print(onTouched)

A for or while loop has no end

Loops open with do and need an end too. The message then says to close 'do'.

Breaks Script in ServerScriptService named Loop
for i = 1, 5 do
	print(i)
print("done")

Close the loop where its body ends.

Fixed Script in ServerScriptService named Loop
for i = 1, 5 do
	print(i)
end
print("done")

An if ... else has no end after the else

else and elseif are part of the same if, which needs one end after the last branch. Leaving it out gives to close 'else'.

Breaks Script in ServerScriptService named Shop
local coins = 50

if coins >= 100 then
	print("You can buy the sword")
else
	print("Not enough coins")

One end after the last branch closes the whole if.

Fixed Script in ServerScriptService named Shop
local coins = 50

if coins >= 100 then
	print("You can buy the sword")
else
	print("Not enough coins")
end

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.

For example: ServerScriptService.Shop:12: Expected 'end' (to close 'function' at line 3), got <eof>

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

  1. A syntax error stops the whole script before its first line runs, so nothing in that script works, not just the broken line.
  2. Open the script. The Script Editor underlines the problem in red; hover over the underline to read the message.
  3. Open Script Analysis (View tab) to see every syntax error in every script, with its line number. Double-click one to jump to it.
  4. 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

How do I know where the end is missing?

Start at the line in (to close '...' at line N). If Luau adds did you forget to close 'then' at line M?, line M is usually the real culprit. Indent each block and look for the one whose end is not lined up with it.

Do elseif and else need their own end?

No. One end after the last branch closes the whole if ... elseif ... else.

What if Luau expected eof (end of file) but got end instead?

That is the opposite problem: one end too many. See the page on that error.

Can RoCode fix it?

Yes. Paste the Output line into RoCode. It opens the script in your open place, finds the block with no end and closes it in the right place.

Sources and further reading

How the code was checked: every block marked Fixed passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 23 October 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 23 October 2026. A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.

Stop hunting errors line by line.

RoCode reads the scripts in your open place, fixes the error where it happens and tells you what it changed. Free every day, no card required.