Erreurs de script (Luau)
Lecture d'un personnage qui n'est pas encore là — Le script lit `player.Character` (ou un membre du personnage) avant que Roblox ne l'ait créé, ou après une mort. `Character` vaut nil pendant ces instants — ils arrivent à chaque entrée de joueur et à chaque respawn. Correction : Passer par `player.Character or player.CharacterAdded:Wait()` puis `character:WaitForChild("Humanoid", 5)`. Se reconnecter à `CharacterAdded` à chaque réapparition au lieu de garder une référence : l'ancien personnage est détruit. Tester la valeur avant usage (`if not humanoid then return end`).
Parenthèses oubliées sur un appel de méthode — On lit une propriété sur une FONCTION au lieu de lire le résultat de son appel : `objet.GetPivot.Position` au lieu de `objet:GetPivot().Position`, ou `UDim2.new.X`. Luau ne dit pas « il manque des parenthèses », il dit qu'on indexe une fonction — c'est le même problème. Correction : Ajouter les parenthèses de l'appel, et le `:` quand c'est une méthode : `objet:GetPivot().Position`, `objet:GetBoundingBox()`, `UDim2.new(0, 0, 0, 0)`. Le nom qui suit `with` dans le message dit quelle propriété on cherchait : remonter de là vers l'appel qui la précède.
WaitForChild qui n'aboutit jamais — L'objet attendu n'existe pas sous ce parent : mauvais chemin, objet renommé, ou instance créée côté serveur que le client ne reçoit pas (elle est dans ServerStorage, ou la réplication est coupée par le streaming). Correction : Vérifier le chemin exact dans l'Explorateur. Donner un délai à `WaitForChild(nom, 10)` et traiter le nil qui revient au lieu d'attendre pour toujours. Ce qui doit être vu du client vit dans ReplicatedStorage, jamais dans ServerStorage ni ServerScriptService.
Appel d'une fonction qui n'existe pas — Le nom appelé n'est pas défini : faute de frappe, module qui ne renvoie pas la table attendue, ou `:` employé à la place de `.` (ou l'inverse) sur une fonction de module. Correction : Vérifier que le ModuleScript se termine bien par `return M`. Une fonction déclarée `function M.faire(a)` s'appelle `M.faire(a)` ; déclarée `function M:faire(a)`, elle s'appelle `M:faire(a)`. Vérifier l'orthographe exacte, Luau est sensible à la casse.
Un ModuleScript a planté au chargement — L'erreur affichée n'est pas la vraie : elle dit seulement qu'un `require` a échoué. La panne est dans le module appelé, à son tout premier passage. Correction : Lire la ligne juste au-dessus dans la console : elle donne le module et la ligne fautives. Souvent un `require` circulaire (A demande B qui demande A) ou un service absent en haut du fichier. Couper le cycle en déplaçant le `require` dans la fonction qui en a besoin.
Calcul sur une valeur absente — Une donnée de joueur lue avant chargement, ou une clé absente d'une table (un profil sauvegardé avant l'ajout de ce champ ne le contient pas). Correction : Donner une valeur par défaut à la lecture : `local or = profil.Or or 0`. À l'ouverture d'une sauvegarde, compléter les champs manquants à partir d'un profil modèle avant de s'en servir — c'est ce qui casse à chaque ajout de fonctionnalité.
Comparaison avec une valeur absente — Même origine que le calcul sur nil : une clé de table absente, ou un attribut d'instance jamais posé. Correction : Lire les attributs avec une valeur de repli : `local prix = objet:GetAttribute("Prix") or 0`. Poser les attributs à la création de l'objet plutôt que d'espérer qu'ils existent.
Parent affecté à nil — Le conteneur visé n'existe pas au moment où on y range l'objet — souvent un dossier créé plus tard, ou cherché avec `FindFirstChild` sans test. Correction : Créer le dossier s'il manque au lieu de le supposer présent, avec un utilitaire du type `local dossier = parent:FindFirstChild(nom) or Instance.new("Folder")`. Ne jamais enchaîner deux `FindFirstChild` sans vérifier le premier.
Mauvais type passé à une API Roblox — Une valeur brute est donnée là où Roblox attend une Instance ou un type précis : un nom de joueur au lieu du joueur, un nombre au lieu d'un Vector3. Correction : Construire le bon type explicitement : `Vector3.new(x, y, z)`, `CFrame.new(...)`, `Players:GetPlayerByName(nom)`. Sur un remote, vérifier `typeof(valeur)` côté serveur avant de s'en servir : le client peut envoyer n'importe quoi.
Membre inexistant — Le chemin est faux, l'objet a été renommé, ou il n'est pas encore répliqué au client quand le script le lit. Correction : Comparer le chemin avec l'Explorateur. Côté client, attendre l'objet (`WaitForChild` avec délai) plutôt que d'y accéder directement. Sur une grande carte, vérifier que le streaming n'a pas encore déchargé la zone.
Argument manquant ou nil — Une fonction est appelée sans tout ce qu'elle attend — souvent après avoir ajouté un paramètre sans mettre à jour tous les appels. Correction : Chercher tous les appels de la fonction et compléter. Sur un remote, ne jamais supposer que le client a envoyé les bons arguments : vérifier chacun avant usage.
Erreurs de réseau et de remotes
FireClient appelé sans joueur — Le premier argument de `FireClient` doit être l'objet Player, pas son nom ni son personnage. Correction : Appeler `remote:FireClient(player, ...)` avec le Player obtenu par `Players:GetPlayerFromCharacter(personnage)`. Pour tout le monde, utiliser `FireAllClients(...)`.
Remote introuvable côté client — Le RemoteEvent est créé côté serveur après que le client l'a cherché, ou il vit ailleurs que dans ReplicatedStorage. Correction : Créer tous les remotes au démarrage du serveur, dans un dossier `ReplicatedStorage/<Jeu>/Remotes`, et les attendre côté client avec `WaitForChild(nom, 10)`. Ne jamais créer un remote depuis le client.
Requêtes HTTP désactivées — HttpService est coupé par défaut sur chaque place. Correction : Fichier → Paramètres du jeu → Sécurité → « Autoriser les requêtes HTTP ». Et vérifier que le jeu a bien besoin d'un service externe : la plupart du temps, un DataStore suffit et coûte moins cher en latence.
Erreurs de sauvegarde (DataStore)
DataStore saturé (file d'attente) — Trop d'écritures pour la même clé : Roblox autorise environ une opération toutes les six secondes par clé. Une sauvegarde à chaque gain de pièce dépasse ce budget en quelques secondes. Correction : Sauvegarder l'état en mémoire et n'écrire qu'aux moments utiles : toutes les 60 à 120 secondes, à la sortie du joueur, et dans `BindToClose`. Utiliser `UpdateAsync` plutôt que `GetAsync` suivi de `SetAsync`, et n'écrire que si quelque chose a changé.
API DataStore refusée — L'accès des API aux services Roblox n'est pas activé pour cette place, ou le jeu n'est pas publié. Correction : Dans Studio : Fichier → Paramètres du jeu → Sécurité → activer « Activer l'accès de Studio aux services API ». Le jeu doit aussi être publié : un place jamais publié n'a pas de DataStore.
Instance envoyée au DataStore — Un DataStore n'accepte que des données simples : nombres, chaînes, booléens, tables de ces types. Ni Instance, ni Vector3, ni CFrame, ni fonction. Correction : Sérialiser avant d'écrire : un Vector3 devient `{x = p.X, y = p.Y, z = p.Z}`, un objet devient son nom ou son identifiant. Reconstruire les instances à la lecture.
Erreurs de performance
Script coupé pour temps d'exécution — Une boucle tourne sans jamais rendre la main : `while true do` sans `task.wait()`, ou une boucle de recherche sur tout le Workspace à chaque image. Correction : Ajouter `task.wait()` dans toute boucle longue. Remplacer les recherches répétées par un index construit une fois (CollectionService, table de tags). Ce qui doit suivre les images passe par `RunService.Heartbeat`, pas par `while true`.
Boucle d'événements infinie — Un gestionnaire modifie la propriété qu'il écoute : `Changed` se redéclenche sans fin. Correction : Garder un drapeau pendant la modification, ou n'écrire que si la valeur diffère réellement. Mieux : écouter un événement dédié plutôt que `Changed` sur une propriété qu'on écrit soi-même.
Erreurs d'interface
Tween sur une propriété impossible — TweenService n'anime que des types numériques (nombre, UDim2, Color3, CFrame, Vector3). Le reste — texte, image, booléen — ne s'anime pas. Correction : Animer la propriété numérique correspondante (`TextTransparency`, `Size`, `BackgroundColor3`) et changer le reste d'un coup. Vérifier l'orthographe exacte de la propriété : elle est sensible à la casse.
Erreurs de sons et d'images
Son ou image qui ne charge pas — L'identifiant d'asset n'existe pas, n'est pas public, ou appartient à un autre créateur qui ne l'a pas partagé. Correction : Vérifier l'identifiant dans le catalogue et qu'il est bien utilisable. Un asset trouvé par recherche doit être inséré, pas recopié à la main. Précharger les sons importants avec `ContentProvider:PreloadAsync` pour que le défaut se voie au chargement, pas en pleine partie.
Erreurs de gameplay
Touched déclenché par autre chose qu'un joueur — `Touched` se déclenche pour tout ce qui touche la pièce : accessoires, outils, autres pièces. Le code suppose un personnage et lit `Humanoid` sur un chapeau. Correction : Remonter au modèle et tester : `local perso = partie.Parent; local humanoid = perso and perso:FindFirstChildOfClass("Humanoid"); if not humanoid then return end`. Ajouter un délai anti-répétition par joueur : `Touched` part plusieurs fois par seconde.
Le joueur meurt et ne revient pas au checkpoint — La position de réapparition est gardée sur le personnage, qui est détruit à la mort ; ou le SpawnLocation utilisé n'est pas celui du joueur. Correction : Garder la progression dans une table indexée par UserId, côté serveur. À `CharacterAdded`, déplacer le personnage avec `PivotTo` sur le checkpoint enregistré, après `WaitForChild("HumanoidRootPart")`.
Questions fréquentes
Pourquoi l'erreur affichée n'est pas toujours la vraie ?
Un échec de require affiche seulement « requested module experienced an error » : la panne réelle est dans le module appelé, et la ligne précédente de la console la donne.
Comment savoir si l'erreur vient du client ou du serveur ?
La console de Studio distingue les deux contextes. Une erreur sur un objet absent côté client alors qu'il existe côté serveur est presque toujours un problème de réplication : l'objet est dans ServerStorage, ou pas encore arrivé.