Erro FiveM json.decode: correções para nil, string vazia e JSON inválido

json.decode falha ou retorna nil em seu script FiveM? Por que decodificar nil, JSON vazio ou editado manualmente quebra, o que json.encode faz com chaves mistas, e como usar pcall com segurança.

O erro aparece uma linha após a decodificação:

text
SCRIPT ERROR: @my_script/server/main.lua:31: attempt to index a nil value (local 'data')
lua
local data = json.decode(row.metadata)
print(data.level)   -- data is nil

json.decode não lhe deu nada utilizável, então a próxima linha indexou nil. A decodificação raramente é a culpa real. A entrada era nil, vazia ou quebrada, ou a tabela que você salvou antes não era o que você pensava. Aqui está como encontrar qual é, e como decodificar com segurança.

1. A string é nil ou vazia

O caso mais comum. O valor que você decodifica não existe ainda:

  • Uma coluna de banco de dados que é NULL. Uma linha sem dados salvos retorna nil para essa coluna.
  • Uma query sem resultado. MySQL.scalar.await(...) e MySQL.single.await(...) retornam nil quando nenhuma linha corresponde. Veja o guia de queries oxmysql para o que cada função retorna.
  • Uma chave KVP que nunca foi definida. GetResourceKvpString('my_key') retorna nil quando a chave não existe, veja KVP de recurso FiveM.
  • Um arquivo que está faltando. LoadResourceFile(GetCurrentResourceName(), 'data.json') retorna nil quando o arquivo não está lá.
  • Uma string vazia. Uma coluna salva como '' também não é um JSON válido.

Decodificar nil ou '' é um bug no chamador, então verifique a string primeiro:

lua
local raw = GetResourceKvpString('my_key')
local data = {}

if raw and raw ~= '' then
    data = json.decode(raw) or {}
end

2. O JSON é inválido

Uma string que está presente ainda pode ser inválida. Causas típicas quando um arquivo ou um valor de banco de dados foi editado manualmente:

  • Uma vírgula à direita após a última entrada: { "a": 1, }
  • Aspas simples em vez de duplas: { 'a': 1 }
  • Comentários no arquivo. JSON não permite.
  • Um bracket ou aspas faltando após copiar parte de um arquivo.
  • Sintaxe Lua colada em um arquivo JSON, como a = 1 ou [1] = 'x'.
  • Um caractere quebrado de um editor de texto, como aspas curvas copiadas de uma página da web.
json
{
  "items": [
    { "name": "water", "count": 2 },
    { "name": "bread", "count": 1 }
  ]
}

Valide o arquivo antes de culpar o script. VS Code sublinha erros JSON conforme você digita, e um validador JSON online mostra a posição exata do erro.

3. Sempre decodifique com pcall

Dependendo da entrada e da build, uma string ruim lança um erro Lua ou volta como nil. Você não precisa lembrar qual: coloque a chamada em uma função para ambos serem tratados.

lua
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)

A verificação type(result) ~= 'table' também captura um valor que é um JSON válido mas não é um objeto, como "hello" ou 5.

Dica: quando uma decodificação falha e você não sabe por quê, imprima a string bruta ao lado de seu tipo: print(type(str), str). Um nil ou uma linha vazia mostra a causa de imediato.

4. json.encode e as chaves que mudam

Uma decodificação pode funcionar e ainda lhe dar os dados errados, porque a tabela foi salva de uma forma que não sobrevive à viagem de ida e volta. JSON tem duas formas: uma lista [...] e um objeto {...} com chaves de texto.

lua
local saved = json.encode({ [100] = 'a', [250] = 'b' })
local loaded = json.decode(saved)

print(loaded[100])     -- nil
print(loaded['100'])   -- 'a'

O que isso significa na prática:

  • Chaves numéricas se tornam chaves de texto quando a tabela é salva como um objeto. Após a decodificação, procure o valor com a chave de texto, ou converta a chave com tonumber.
  • Arrays esparsos com buracos ({ [1] = 'a', [3] = 'c' }) não são uma lista limpa, então podem ser escritos como um objeto em vez de um array.
  • Tabelas mistas, com itens de lista e chaves nomeadas, não mapeiam nitidamente para nenhuma forma. Mantenha uma lista como uma lista, e coloque os campos nomeados em uma tabela separada.
  • Funções, userdata e vetores não podem ser escritos como dados JSON simples. Converta um vetor para { x = v.x, y = v.y, z = v.z } antes de codificá-lo.
  • Uma tabela vazia é geralmente escrita como [], então leia-a de volta como uma lista ou uma tabela vazia, não como um objeto.

Uma maneira segura de armazenar coordenadas:

lua
-- 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)
end

Use json.encode(value, { indent = true }) enquanto depura, pois é muito mais fácil de ler.

5. Decodifique uma vez e verifique o tipo

Os dados de um banco de dados podem chegar ao seu script como uma string em um lugar e como uma tabela em outro. Algumas bibliotecas e frameworks decodificam colunas JSON para você, outras retornam o texto bruto. Antes de decodificar, verifique o que você tem:

lua
local meta = row.metadata
if type(meta) == 'string' then
    meta = safeDecode(meta)
end
meta = meta or {}

Decodificar algo que já é uma tabela é um bug, e uma verificação de tipo não custa nada.

Lista de verificação

Sintoma Solução
attempt to index a nil value (local 'data') após decodificação A string era nil ou inválida; verifique-a antes de decodificar e use pcall
Decodificação de uma coluna de banco de dados NULL e resultados sem linha são nil; proteja com if raw and raw ~= ''
Uma leitura KVP não retorna nada A chave nunca foi definida; use uma tabela padrão
Um arquivo editado manualmente falha Remova vírgulas à direita, comentários e aspas simples; valide-o em um editor
Chaves numéricas perdidas após decodificação As chaves JSON são texto; leia t['100'] ou converta com tonumber
Vetores escritos como JSON Salve x, y e z como campos separados

Respostas rápidas

Por que json.decode retorna nil ou lança um erro?

A string é nil, vazia, ou não é um JSON válido. Dependendo do caso, ela lança um erro ou não retorna nada, então coloque a chamada em pcall e verifique o resultado.

Por que minhas chaves numéricas são strings após json.decode?

As chaves de objeto JSON são sempre texto. Uma tabela como { [100] = true } é salva como um objeto com a chave de texto 100 e volta com a chave '100', então data[100] é nil.

Como verifico se um arquivo JSON é válido?

Abra-o em VS Code, que marca erros JSON no editor, ou cole-o em um validador JSON online. Os erros usuais são uma vírgula à direita, aspas simples ou um comentário.

Scripts sem esse problema

Item Creator V2Crie itens usáveis com animações, props, efeitos e muito mais — sem escrever código.Ver script →Shop CreatorMonte uma loja em menos de um minuto — donos, funcionários, cofres e assaltos inclusos.Ver script →Quest CreatorUm editor visual de missões e diálogos com NPCs, montado nó por nó dentro do jogo.Ver script →

Continue lendo