FiveM json.decode error: nil, empty string and invalid JSON fixes
json.decode fails or returns nil in your FiveM script? Why decoding nil, empty or hand-edited JSON breaks, what json.encode does to mixed keys, and how to use pcall safely.
The error appears one line after the decode:
SCRIPT ERROR: @my_script/server/main.lua:31: attempt to index a nil value (local 'data')local data = json.decode(row.metadata)
print(data.level) -- data is niljson.decode gave you nothing usable, so the next line indexed nil. The decode is rarely the real fault. The input was nil, empty or broken, or the table you saved earlier was not what you thought. Here is how to find which, and how to decode safely.
1. The string is nil or empty
The most common case. The value you decode does not exist yet:
- A database column that is
NULL. A row with no saved data returnsnilfor that column. - A query with no result.
MySQL.scalar.await(...)andMySQL.single.await(...)returnnilwhen no row matches. See the oxmysql queries guide for what each function returns. - A KVP key that was never set.
GetResourceKvpString('my_key')returnsnilwhen the key does not exist, see FiveM resource KVP. - A file that is missing.
LoadResourceFile(GetCurrentResourceName(), 'data.json')returnsnilwhen the file is not there. - An empty string. A column saved as
''is not valid JSON either.
Decoding nil or '' is a bug in the caller, so check the string first:
local raw = GetResourceKvpString('my_key')
local data = {}
if raw and raw ~= '' then
data = json.decode(raw) or {}
end2. The JSON is invalid
A string that is present can still be invalid. Typical causes when a file or a database value was edited by hand:
- A trailing comma after the last entry:
{ "a": 1, } - Single quotes instead of double quotes:
{ 'a': 1 } - Comments in the file. JSON does not allow them.
- A missing bracket or quote after copying part of a file.
- Lua syntax pasted into a JSON file, such as
a = 1or[1] = 'x'. - A broken character from a text editor, such as curly quotes copied from a web page.
{
"items": [
{ "name": "water", "count": 2 },
{ "name": "bread", "count": 1 }
]
}Validate the file before you blame the script. VS Code underlines JSON errors as you type, and an online JSON validator shows the exact position of the fault.
3. Always decode with pcall
Depending on the input and the build, a bad string either raises a Lua error or comes back as nil. You do not need to remember which: wrap the call so both are handled.
local function safeDecode(str)
if type(str) ~= 'string' or str == '' then
return nil
end
local ok, result = pcall(json.decode, str)
if not ok or type(result) ~= 'table' then
return nil
end
return result
end
local data = safeDecode(row.metadata) or {}
print(data.level)The type(result) ~= 'table' check also catches a value that is valid JSON but not an object, such as "hello" or 5.
Tip: when a decode fails and you do not know why, print the raw string next to its type:
print(type(str), str). Anilor an empty line shows the cause at once.
4. json.encode and the keys that change
A decode can work and still give you the wrong data, because the table was saved in a form that does not survive the round trip. JSON has two shapes: a list [...] and an object {...} with text keys.
local saved = json.encode({ [100] = 'a', [250] = 'b' })
local loaded = json.decode(saved)
print(loaded[100]) -- nil
print(loaded['100']) -- 'a'What this means in practice:
- Numeric keys become text keys when the table is saved as an object. After decode, look the value up with the text key, or convert the key with
tonumber. - Sparse arrays with holes (
{ [1] = 'a', [3] = 'c' }) are not a clean list, so they can be written as an object instead of an array. - Mixed tables, with both list items and named keys, do not map cleanly to either shape. Keep a list as a list, and put named fields in a separate table.
- Functions, userdata and vectors cannot be written as plain JSON data. Convert a vector to
{ x = v.x, y = v.y, z = v.z }before you encode it. - An empty table is usually written as
[], so read it back as a list or an empty table, not as an object.
A safe way to store coordinates:
-- save
local payload = json.encode({ x = coords.x, y = coords.y, z = coords.z })
-- load
local pos = safeDecode(payload)
if pos then
SetEntityCoords(ped, pos.x, pos.y, pos.z, false, false, false, false)
endUse json.encode(value, { indent = true }) while debugging, since it is far easier to read.
5. Decode once, and check the type
Data from a database may reach your script as a string in one place and as a table in another. Some libraries and frameworks decode JSON columns for you, others return the raw text. Before you decode, check what you hold:
local meta = row.metadata
if type(meta) == 'string' then
meta = safeDecode(meta)
end
meta = meta or {}Decoding something that is already a table is a bug, and a type check costs nothing.
Checklist
| Symptom | Fix |
|---|---|
attempt to index a nil value (local 'data') after decode |
The string was nil or invalid; check it before decoding and use pcall |
| Decoding a database column | NULL and no-row results are nil; guard with if raw and raw ~= '' |
| A KVP read gives nothing | The key was never set; use a default table |
| A hand-edited file fails | Remove trailing commas, comments and single quotes; validate it in an editor |
| Number keys lost after decode | JSON keys are text; read t['100'] or convert with tonumber |
| Vectors written as JSON | Save x, y and z as separate fields |
Quick answers
Why does json.decode return nil or throw an error?
The string is nil, empty, or not valid JSON. Depending on the case it either raises an error or returns nothing, so wrap the call in pcall and check the result.
Why are my numeric keys strings after json.decode?
JSON object keys are always text. A table like { [100] = true } is saved as an object with the text key 100 and comes back with the key '100', so data[100] is nil.
How do I check that a JSON file is valid?
Open it in VS Code, which marks JSON errors in the editor, or paste it into an online JSON validator. The usual faults are a trailing comma, single quotes or a comment.
Scripts that skip this problem
Item Creator V2Create usable items with animations, props, effects and more β without writing code.View script β
Shop CreatorBuild a shop in under a minute β owners, employees, vaults and robberies included.View script β
Quest CreatorA visual editor for quests and NPC dialogues, built node by node in game.View script β