tentative de comparer un nombre avec nil / opération arithmétique sur une valeur nil : correction

Corrigez « attempt to compare number with nil » et « arithmetic on a nil value » dans FiveM : données de joueur non chargées, valeurs de config manquantes, tonumber et defaults sûrs avec `or`.

Sortie de la console :

text
SCRIPT ERROR: @my_script/server/main.lua:58: attempt to compare number with nil
SCRIPT ERROR: @my_script/client/main.lua:91: attempt to perform arithmetic on a nil value (field 'money')

Une ligne du script utilise une valeur qui n'existe pas encore dans une comparaison ou un calcul. Voici ce qui laisse généralement la valeur vide, et comment rendre le script sûr.

Ce que l'erreur signifie

Lua vous donne nil pour toute variable ou entrée de table qui n'a pas de valeur. Comparer (<, >, <=) ou calculer (+, -, *, /) avec nil arrête le script avec un de ces messages :

  • attempt to compare number with nil (ou attempt to compare nil with number) : un côté de la comparaison est nil.
  • attempt to perform arithmetic on a nil value : un calcul utilise une variable nil. Quand Lua connaît le nom, il l'ajoute, comme (field 'money') ou (local 'price').

Le numéro de ligne dans le message est la ligne avec la comparaison ou la somme. Le nil est l'une des valeurs de cette ligne. Imprimez-les pour voir lequel :

lua
print('price', price, type(price))
print('count', count, type(count))
if price > count then
    -- ...
end

1. Les données du joueur ne sont pas encore chargées

La cause la plus courante : le script lit le joueur avant que le framework ait fini de le charger, par exemple dans les premières lignes d'un fichier, ou dans un thread qui démarre immédiatement.

lua
-- runs too early on the client: money is nil
local money = ESX.GetPlayerData().money
if money > 100 then
    -- ...
end

Attendez l'événement chargé du framework, et lisez les données de là :

lua
-- ESX client
local PlayerData = {}

RegisterNetEvent('esx:playerLoaded', function(xPlayer)
    PlayerData = xPlayer
end)
lua
-- QBCore client
local QBCore = exports['qb-core']:GetCoreObject()
local PlayerData = {}

RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
    PlayerData = QBCore.Functions.GetPlayerData()
end)

Sur le serveur, un objet joueur peut aussi être nil quand l'id est faux ou que le joueur a quitté. Vérifiez-le avant de l'utiliser :

lua
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return end
lua
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return end

Sur QBox, l'équivalent est exports.qbx_core:GetPlayer(source), avec la même vérification nil.

Conseil : si le script redémarre pendant que vous êtes sur le serveur, playerLoaded a déjà été déclenché et ne se déclenchera pas à nouveau. Lisez les données une fois quand la resource démarre aussi.

2. Une valeur de config manque

Vous avez ajouté une ligne à config.lua que le script n'a pas, ou le script lit une clé que votre ancienne config ne contient pas. Après une mise à jour, un vieux config.lua est une cause très courante.

lua
-- config.lua of the old version has no Config.Price
if playerMoney >= Config.Price then
    -- ...
end

Comparez votre config avec celle livrée avec la nouvelle version, et ajoutez les clés manquantes. Dans votre propre code, donnez à chaque paramètre une valeur par défaut :

lua
local price = Config.Price or 100

3. La valeur est une chaîne, pas un nombre

Les valeurs d'une base de données, d'une boîte d'entrée dans un menu ou d'un message JSON arrivent souvent comme du texte. Comparer une chaîne avec un nombre donne une erreur différente (attempt to compare number with string), mais une conversion qui échoue vous donne nil, ce qui ramène cette erreur. tonumber convertit, et retourne nil quand il ne peut pas :

lua
local amount = tonumber(data.amount)
if not amount then
    return -- not a number: stop here
end

4. Utilisez or pour une valeur par défaut

or retourne le côté droit quand le côté gauche est nil (ou false). C'est le moyen le plus court de rendre un calcul sûr :

lua
local count = tonumber(data.count) or 0
local total = (item.price or 0) * count

Utilisez-le où une valeur manquante peut vraiment signifier zéro, comme un bonus optionnel. Où une valeur manquante est un bug, par exemple un prix qui doit exister, arrêtez avec un message clair au lieu de le cacher :

lua
local price = Config.Items[name] and Config.Items[name].price
if not price then
    print(('no price set for %s'):format(name))
    return
end

5. Un résultat de base de données ou de callback est vide

Une query qui ne trouve pas de ligne donne nil ou une table vide. Lire une colonne de celle-ci échoue :

lua
local row = MySQL.single.await('SELECT balance FROM bank WHERE owner = ?', { identifier })
if row.balance > 0 then   -- row is nil when the player has no row
    -- ...
end

Vérifiez d'abord la ligne :

lua
local row = MySQL.single.await('SELECT balance FROM bank WHERE owner = ?', { identifier })
local balance = row and row.balance or 0

Il en va de même pour les serveurs callbacks : la réponse peut être nil si le callback n'a pas été trouvé ou n'a rien retourné. Si votre script attend un callback, gérez ce cas. Connexe : attempt to call a nil value est l'erreur sœur quand une fonction, pas une valeur, manque.

6. Une faute de frappe dans un nom de champ

xPlayer.money et xPlayer.Money sont différents. Il en va de même pour price et Price. Le message d'erreur nomme souvent le champ : vérifiez son orthographe par rapport à la documentation du framework ou par rapport à la table que vous imprimez avec print(json.encode(data)).

Liste de contrôle

Symptôme Correction
Erreur juste après avoir rejoint Attendez l'événement player loaded avant de lire les données du joueur
xPlayer ou Player est nil sur le serveur Vérifiez if not xPlayer then return end et l'id source
Erreur après la mise à jour d'un script Ajoutez les nouvelles clés du config.lua fourni au vôtre
La valeur provient d'un menu ou JSON Convertissez avec tonumber(value) et vérifiez qu'elle n'est pas nil
Une valeur peut manquer exprès Utilisez value or 0 comme valeur par défaut
La query de base de données ne retourne rien Vérifiez que la ligne n'est pas nil avant de lire ses colonnes
Le champ est nil même s'il devrait exister Vérifiez l'orthographe et les majuscules

Réponses rapides

Que signifie « attempt to compare number with nil » ?

Une ligne compare un nombre avec quelque chose qui n'a pas de valeur, comme price > 100 quand price est nil. Trouvez quelle variable est nil et pourquoi elle n'a jamais été définie.

Comment donner une valeur par défaut à une variable en Lua ?

Utilisez or : local count = tonumber(value) or 0. Si la valeur est nil ou pas un nombre, count devient 0.

Pourquoi cela ne se produit-il que juste après que je rejoigne le serveur ?

Le script lit les données du joueur avant que le framework les ait chargées. Attendez l'événement du joueur chargé, ou vérifiez que l'objet du joueur n'est pas nil avant de le lire.

Des scripts sans ce problème

Shop CreatorCréez un magasin en moins d’une minute — propriétaires, employés, coffres et braquages inclus.Voir le script →Pawn Shop AppUn marché de prêt sur gage entre joueurs, directement dans lb-phone.Voir le script →Quest CreatorUn éditeur visuel de quêtes et de dialogues PNJ, construit nœud par nœud en jeu.Voir le script →

À lire aussi