Roblox Studio error

attempt to concatenate string with nil

What attempt to concatenate string with nil 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 readErrorLuau

In short

.. joins text, and it only accepts strings and numbers. The two types in the message are the left and right side: string with nil means the value on the right of .. was missing. Find out why it is nil, or turn it into text on purpose with tostring() or a backtick string such as `Coins: {coins}`, which never errors.

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)
StarterGui.ScreenGui.Coins.Label:6: attempt to concatenate string with nil

Other forms of the same message:

  • attempt to concatenate nil with string
  • attempt to concatenate string with Instance
  • attempt to concatenate string with boolean

Numbers are turned into text for you ("Coins: " .. 5 works). Everything else is not: nil, booleans, tables and Roblox objects all stop the script.

For a Roblox object, the message says Instance. You almost always wanted its .Name or one of its values, not the object.

Causes and fixes

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

The value is nil

A value read from a table, an attribute or FindFirstChild can be nil. Joining it with .. fails, often in a UI label or a print you added to debug something else.

Breaks LocalScript in a TextLabel in StarterGui named Label
local label = script.Parent

local stats = { Coins = 120 }
-- "Gems" was never set: attempt to concatenate string with nil
label.Text = "Gems: " .. stats.Gems

Give the missing value a default, or skip the line when it is missing. Backtick strings print nil instead of failing, which is handy for debug prints.

Fixed LocalScript in a TextLabel in StarterGui named Label
local label = script.Parent :: TextLabel

local stats: { [string]: number } = { Coins = 120 }
local gems = stats.Gems or 0
label.Text = `Gems: {gems}`

An object was joined instead of its Name

A Player, Part or Tool is an Instance. "Hello " .. player gives attempt to concatenate string with Instance.

Breaks Script in ServerScriptService named Welcome
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
	-- attempt to concatenate string with Instance
	print("Welcome " .. player)
end)

Use the property you meant: player.Name, player.DisplayName or part.Name.

Fixed Script in ServerScriptService named Welcome
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player: Player)
	print("Welcome " .. player.DisplayName)
end)

A true/false or a table was joined

.. does not turn true, false or a table into text. Settings flags and lists are the usual ones.

Breaks Script in ServerScriptService named Settings
local settings = { Music = true, Volume = 0.5 }

-- attempt to concatenate string with boolean
print("Music on: " .. settings.Music)

Wrap it in tostring(), or use a backtick string. For a list, join its items with table.concat.

Fixed Script in ServerScriptService named Settings
local settings = { Music = true, Volume = 0.5 }
local items = { "Sword", "Shield" }

print("Music on: " .. tostring(settings.Music))
print(`Volume: {settings.Volume}`)
print("Items: " .. table.concat(items, ", "))

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: StarterGui.ScreenGui.Coins.Label:6: attempt to concatenate string with nil

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. Open Output (Window menu, or the Script tab), clear it with Ctrl+K (⌘K on Mac), and press Play.
  2. Find the first red line. It starts with the script's place in the Explorer and the line number, such as ServerScriptService.Shop:12:.
  3. Click the red line. Studio opens that script with the cursor on the failing line.
  4. Read the lines between Stack Begin and Stack End under it: they list the calls that led there, newest first, so you can see which function called the broken one.
  5. Still not sure which value is wrong? Add print(typeof(x), x) just above the line, or set a breakpoint on it and read the values in the Watch window.

Questions

Which side is nil?

The message lists the left side first, then the right. string with nil means the right side of .. was nil; nil with string means the left side.

What is the safest way to build text in Luau?

Backtick strings: `Coins: {coins}`. They call tostring on each value for you, so a nil prints as nil instead of stopping the script.

Why does joining a number work but not a boolean?

Luau turns numbers into text for .., but not booleans, nil, tables or objects. Use tostring() for those.

Can RoCode fix it?

Yes. Paste the Output line into RoCode. It finds the line in the script in your open place and fixes the value or the text, for example using .Name or a default.

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 and fails only when it runs. The message wording was checked by running the broken code with the Luau command line tool and against the message strings in Roblox Studio itself 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.