Accueil·Messages d’erreur

Les messages d’erreur, expliqués

104 messages d’erreur : ce qu’ils veulent dire, pourquoi ils surviennent, quoi faire.

Les correctifs ont un coût. git reset --hard jette le travail non validé, un push forcé peut détruire les commits d’un collègue, et docker system prune supprime les volumes sans nom. Là où c’est le cas, la fiche le dit.

Git29

Presque toutes les erreurs de git sont un refus qui signifie « faire cela depuis cet état ferait perdre quelque chose » ; fatal: veut dire que git s'est arrêté sans rien modifier, et les lignes hint: sous la première portent souvent le vrai remède.

fatal: refusing to merge unrelated historiesLes deux côtés que vous fusionnez n'ont aucun ancêtre commun : pour git, ce sont deux histoires étrangères l'une à l'autre. Cela arrive quand vous avez démarré en local avec git init, fait quelques commits, puis ajouté un dépôt distant qui avait déjà ses propres commits avant de faire un pull. --allow-unrelated-histories les fusionne bien, mais il soude deux histoires étrangères en un seul commit, ce qui est très difficile à défaire ensuite ; avec seulement quelques commits locaux, il est plus propre de cloner le distant à neuf et d'y recopier vos fichiers.Your branch and 'origin/main' have divergedVotre branche et origin/main détiennent chacune des commits que l'autre n'a pas : la ligne d'historique s'est scindée en deux. Cela survient quand vous avez committé en local pendant que quelqu'un poussait, ou quand vous avez réécrit avec amend ou rebase des commits déjà poussés. git pull --rebase rejoue vos commits par-dessus les leurs et garde un historique linéaire, mais il donne de nouveaux hachages à vos commits : si vous les aviez déjà partagés, le même travail figure deux fois ; dans ce cas --no-rebase, qui laisse un seul commit de fusion, est plus sûr.fatal: Need to specify how to reconcile divergent branches.Depuis git 2.34, pull refuse de deviner entre fusion et rebase quand les branches ont divergé : il réclame un réglage, il ne signale pas une avarie. Le message apparaît quand les branches ont divergé et que pull.rebase n'a jamais été configuré. pull.ff only est la réponse la plus sûre car il ne tire que s'il peut avancer et s'arrête sinon sans rien créer ; pull.rebase true réécrit chaque fois les hachages de vos commits locaux, et false laisse un commit de fusion.CONFLICT (content): Merge conflict in src/app.tsxLes deux côtés ont modifié les mêmes lignes différemment et git ne peut pas trancher : il a écrit les deux versions dans le fichier, entre <<<<<<<, ======= et >>>>>>>, puis s'est arrêté. Cela arrive quand vous et quelqu'un d'autre éditez la même zone, ou quand un rebase fait passer votre commit par-dessus une modification de ces lignes. Ouvrez le fichier, mettez-le dans l'état voulu, supprimez les marqueurs, puis git add et commit. git merge --abort vous ramène exactement à l'état d'avant la fusion, sans danger pour ce qui est déjà committé, mais il jette les résolutions faites à la main.Please commit your changes or stash them before you merge.Des fichiers où vous avez des modifications non committées sont aussi touchés par les commits entrants, et git a préféré s'arrêter plutôt que les écraser. Le message apparaît lors d'un pull ou d'un merge avec un arbre de travail sale. git stash push -u met ces modifications de côté pour laisser passer la fusion, et -u embarque aussi les fichiers non suivis ; mais git stash pop peut créer un conflit au retour, et un stash reste invisible à côté des branches, donc facile à oublier et à perdre — un commit jetable est l'habitude la plus sûre.error: Your local changes to the following files would be overwritten by checkout:Vous voulez passer sur une autre branche, mais des fichiers dont le contenu diffère là-bas portent encore des modifications non committées. Le message apparaît lors d'un switch ou d'un checkout alors que le travail est à moitié fait. git stash push -u, ou un commit jetable, vous fait traverser et vous laisse y revenir. Le git checkout --force et le git switch --discard-changes qu'on trouve dans les résultats de recherche vous déplacent bien, mais suppriment définitivement ces modifications non committées : rien ne les conserve, pas même le reflog, il n'y a aucun retour possible.You are currently rebasing branch 'feature' on '8a3f21c'.Un rebase a démarré et s'est arrêté en chemin ; HEAD est garé sur un état temporaire et non sur votre branche. Vous voyez cette ligne après un conflit pendant le rebase, ou après un arrêt edit ou break de git rebase -i, quand vous êtes parti faire autre chose sans le terminer. Résolvez le conflit, faites git add et poursuivez avec git rebase --continue, ou utilisez --skip si vous voulez abandonner ce commit. git rebase --abort vous replace exactement là où vous étiez avant le rebase : rien de committé n'est perdu, mais les résolutions déjà faites disparaissent avec.You are in 'detached HEAD' state.HEAD désigne directement un commit et non un nom de branche : tout commit fait ici ne reçoit aucun nom. On arrive là en faisant un checkout d'un hachage ou d'une étiquette, en travaillant dans un sous-module, ou parce que la CI a extrait un commit précis. Pour garder ce que vous avez fait, git switch -c nom crée une branche ici même et ne perd rien. Si vous partez simplement avec git switch main, plus rien ne pointe vers vos commits : le reflog les retrouve encore un temps, puis le ramasse-miettes les efface.Warning: you are leaving 1 commit behind, not connected to any of your branches:Il vous avertit que vous avez committé en état detached HEAD et que vous partez, sans qu'aucune branche ne pointe vers ces commits. Cela survient quand vous avez extrait un hachage, travaillé, committé, puis regagné une branche. Utilisez le hachage affiché dans le message : git branch rescue 8a3f21c les rattache à un nom, et cette commande ne change rien d'autre, elle ajoute seulement un nom. Si vous êtes déjà parti, git reflog les liste encore, mais des commits vers lesquels rien ne pointe disparaissent au passage du ramasse-miettes, soit une trentaine de jours par défaut.error: failed to push some refs to 'https://github.com/user/repo.git'Le serveur a refusé votre push, et cette ligne n'est qu'un résumé : la vraie raison figure dans la ligne ! [rejected] juste au-dessus. Le plus souvent le distant possède des commits que vous n'avez pas, mais une branche protégée, un hook côté serveur ou une limite de taille de fichier donnent le même résumé. Lisez d'abord la raison ; dans le cas ordinaire, git pull --rebase && git push règle tout. Le geste dangereux est d'ajouter --force sans lire, car cela peut effacer du serveur les commits d'un collègue.! [rejected] main -> main (fetch first)La branche distante contient des commits que votre clone n'a jamais vus : pousser maintenant ne serait pas une avance rapide. Cela arrive quand un collègue a poussé avant vous, ou quand votre dernier fetch est ancien. git pull --rebase origin main récupère ces commits et rejoue les vôtres par-dessus, puis le push passe. N'utilisez jamais --force ici : les commits que vous écraseriez appartiennent à quelqu'un d'autre et ne sont pas du tout dans votre dépôt, donc rien en local ne peut les récupérer.! [rejected] main -> main (non-fast-forward)Votre branche n'est pas un descendant de la branche distante : pousser tel quel ferait tomber de l'historique des commits présents sur le serveur. Cela arrive quand vous avez réécrit avec rebase, amend ou reset des commits déjà poussés. Si la réécriture est voulue et que la branche n'est qu'à vous, utilisez git push --force-with-lease : il refuse si le distant a bougé depuis votre dernier fetch, donc contrairement à --force seul il ne peut pas effacer en silence le push d'un collègue arrivé entretemps. Si la réécriture n'était pas voulue, la réponse est pull --rebase, pas la force.Updates were rejected because the remote contains work that you do not have locally.C'est l'explication derrière un push refusé : le distant contient du travail que votre clone n'a pas, et pousser maintenant le supprimerait. Le message apparaît quand plusieurs personnes partagent une branche, ou quand vous avez modifié et committé un fichier depuis l'interface web sans jamais le récupérer. Faites d'abord git pull --rebase origin main puis push, et tout passe. Ajouter --force au mépris de ce conseil fait exactement ce que le conseil vise à empêcher : les commits de l'autre personne disparaissent du serveur et, si personne n'a fait de fetch après son push, ils n'existent plus nulle part.error: src refspec main does not match anyLe nom que vous avez demandé à pousser n'existe localement ni comme branche ni comme étiquette, et on ne peut pas envoyer ce qui n'est pas là. Cela arrive dans un dépôt tout neuf sans aucun commit, où main n'existe pas encore ; ou quand votre branche locale s'appelle master alors que vous avez tapé main ; ou tout simplement à cause d'une faute de frappe. git push -u origin HEAD envoie la branche sur laquelle vous vous trouvez réellement, sous son vrai nom, et règle le cas du nom qui ne correspond pas d'un seul coup. S'il n'y a aucun commit, faites-en un d'abord : un dépôt vide n'a rien à envoyer.fatal: The current branch feature has no upstream branch.Cette branche n'a aucune contrepartie distante enregistrée : un git push ou git pull sans argument ne sait pas où aller. Cela arrive quand vous avez créé une branche avec git switch -c sans jamais la pousser. git push --set-upstream origin feature crée la branche sur le serveur et enregistre l'appariement une fois pour toutes ; ensuite, un simple git push suffit. La commande n'écrit qu'une ligne de configuration locale et une nouvelle branche sur le serveur : elle ne supprime rien et se répète sans risque.error: cannot lock ref 'refs/remotes/origin/main': is at 8a3f21c but expected 1c2d3e4Au moment d'écrire une nouvelle valeur dans une référence de suivi distant, git y a trouvé une valeur différente de celle qu'il venait de lire et a refusé d'écraser. Cela arrive souvent quand votre éditeur fait un fetch en arrière-plan pendant que vous en faites un aussi, ou quand quelqu'un a fait un force push et que vos références de suivi sont décalées. Relancer le fetch suffit généralement. git remote prune origin nettoie les références de suivi dont les branches n'existent plus en amont ; il ne supprime que les copies internes à votre dépôt et ne touche jamais une branche du serveur.fatal: not a git repository (or any of the parent directories): .gitIl n'y a pas de .git dans ce répertoire ni dans aucun répertoire au-dessus : git n'a trouvé aucun dépôt. Cela arrive quand vous êtes un niveau au-dessus ou au-dessous du dépôt, quand un clone a atterri dans un autre dossier, ou quand vous n'avez jamais lancé git init. Vérifiez d'abord où vous êtes avec pwd, et n'utilisez git init que si vous voulez vraiment démarrer un dépôt ici. Lancer git init dans un sous-dossier d'un dépôt existant crée un second dépôt imbriqué qui masque silencieusement celui du dessus, et dès lors les fichiers de ce dossier n'entrent plus dans les commits extérieurs.fatal: remote origin already exists.Le nom origin est déjà utilisé dans ce dépôt : impossible de le créer une seconde fois. Un dépôt cloné possède origin dès le départ, et le message apparaît quand vous y suivez un guide destiné aux nouveaux dépôts et lancez git remote add origin. Regardez d'abord où pointe origin avec git remote -v ; si vous voulez une autre URL, git remote set-url origin ne change que la destination. Ce réglage est une ligne de .git/config, réversible à tout moment et sans effet sur vos commits.error: pathspec 'featue' did not match any file(s) known to gitgit n'a trouvé ni fichier, ni branche, ni étiquette de ce nom — la chaîne entre guillemets est exactement ce qu'il a cherché. Cela arrive sur une faute de frappe, quand la branche n'existe que sur le serveur et que vous n'avez pas fait de fetch, ou quand le fichier se trouve dans un autre répertoire que celui supposé. Pour une branche : git fetch puis git branch -a, et comparez le nom à l'œil ; pour un fichier, git status --short montre les vrais chemins. Les chemins des commandes git se lisent relativement au répertoire où vous êtes, et non à la racine du dépôt, ce qui explique à lui seul beaucoup de ces cas.git@github.com: Permission denied (publickey).ssh a bien atteint le serveur mais n'a présenté aucune clé que le serveur accepte : c'est de l'authentification, pas du réseau. Cela arrive quand vous n'avez pas généré de clé, quand vous en avez une mais ne l'avez jamais ajoutée à ssh-agent, ou quand la clé publique n'est pas enregistrée sur votre compte chez cet hébergeur. ssh-add ~/.ssh/id_ed25519 charge la clé dans l'agent pour cette session, et ssh -T git@github.com indique quelle clé a été essayée et sous quelle identité vous êtes reconnu. Les deux commandes ne font que lire ; il n'y a rien à perdre.remote: Support for password authentication was removed on August 13, 2021.GitHub a cessé d'accepter les mots de passe de compte via https en 2021 : votre mot de passe n'est pas faux, c'est la méthode qui n'est plus acceptée. Le message apparaît quand votre identifiant enregistré est un ancien mot de passe, ou quand vous en avez saisi un à l'invite. Pour rester en https, mettez un personal access token dans le champ mot de passe ; sinon, basculez sur l'adresse ssh avec git remote set-url origin. Changer l'adresse distante n'est qu'une ligne de configuration de votre clone : cela ne touche aucun commit et se défait à tout moment.fatal: Authentication failed for 'https://github.com/user/repo.git/'L'identifiant envoyé a été refusé : il est faux, expiré, ou c'est un jeton sans la portée dont ce dépôt a besoin. Le piège courant est un jeton expiré toujours en cache dans votre assistant d'identifiants : il est envoyé sans jamais vous demander quoi que ce soit, d'où la même ligne à chaque fois. La ligne git credential reject du correctif supprime uniquement cette entrée enregistrée, pour que la question revienne et que vous puissiez coller un jeton neuf. Elle n'efface que l'identifiant sauvegardé et ne touche à aucune donnée du dépôt.fatal: Unable to create '/repo/.git/index.lock': File exists.git crée .git/index.lock comme verrou pendant qu'il écrit l'index : si le fichier est déjà là, un autre git tourne ou l'un d'eux est mort en le laissant. Il subsiste à cause d'un éditeur ou d'un IDE qui lance git en arrière-plan, ou d'une commande interrompue par Ctrl+C ou tuée. Vérifiez qu'aucun git ne tourne, puis supprimez-le avec rm -f .git/index.lock. Le supprimer alors qu'un processus git travaille vraiment peut corrompre l'index, donc vérifiez d'abord ; si l'index finit faussé, git reset le reconstruit depuis HEAD, et sans --hard il laisse vos fichiers intacts.nothing to commit, working tree cleanCe n'est pas une erreur : git vous dit que rien ne diffère du dernier commit, il n'a donc rien fait. Vous le voyez quand le fichier modifié est attrapé par .gitignore, quand l'endroit modifié est un autre clone ou worktree que celui où vous vous trouvez, ou quand vous avez déjà committé et l'avez oublié. git check-ignore -v <chemin> affiche la ligne exacte de .gitignore qui masque un fichier, et git log -1 montre si la modification est déjà passée. Les deux commandes ne font que lire.error: unable to unlink old 'dist/main.js': Permission deniedUn checkout voulait remplacer un fichier par une nouvelle version et le système d'exploitation a refusé de supprimer l'ancien. Cela arrive quand un autre programme garde le fichier ouvert, ce qui est surtout fréquent sous Windows, ou quand vous n'avez pas le droit d'écriture sur le répertoire. Fermez ce qui le retient — serveur de développement, éditeur, antivirus — et relancez la même commande ; sous Unix, corrigez les droits du répertoire. Répéter la commande est sans danger, mais notez que git s'est arrêté en chemin : l'arbre de travail reste à moitié mis à jour jusqu'à la réussite.fatal: bad object 8a3f21cLe nom fourni ne se résout vers rien que git puisse lire : soit l'objet n'est pas dans ce dépôt, soit il y est et il est abîmé. Cela arrive avec un hachage copié d'un autre clone ou d'un clone superficiel, avec un hachage tronqué trop court, ou avec un objet réellement corrompu après un incident disque. git fsck --full signale les objets manquants et cassés en lecture seule, et un hachage venu d'ailleurs exige un git fetch avant que l'objet existe ici. Si fsck signale bien une corruption, recloner est plus rapide et plus sûr que réparer — copiez d'abord vos fichiers non committés en lieu sûr.warning: LF will be replaced by CRLF in package.json.C'est un avis, pas une erreur : core.autocrlf est actif, git stocke donc du LF dans le commit mais écrira du CRLF dans votre copie de travail. Installer git sous Windows avec les valeurs par défaut met autocrlf à true, d'où ce message à chaque add sur cette machine. git config core.autocrlf input stocke du LF et cesse de convertir à l'extraction, et la meilleure réponse est un .gitattributes dans le dépôt contenant * text=auto eol=lf, pour que tous les clones se comportent pareil. Changer le réglage peut faire paraître tous les fichiers modifiés une fois ; c'est une seule réextraction, pas du travail perdu.The file will have its original line endings in your working directoryC'est la seconde moitié de l'avis CRLF ci-dessus : le fichier sur le disque conserve les fins de ligne qu'il a déjà, et seule la copie enregistrée dans le commit est normalisée. Cela vient du même réglage autocrlf, donc rien n'est cassé en soi. Mais si les diffs montrent des fichiers entiers modifiés, c'est le signe que les fins de ligne diffèrent dans l'équipe : figez la règle avec un .gitattributes dans le dépôt et lancez git add --renormalize . une fois. Cette commande ne réécrit que la façon de stocker les fins de ligne, pas le contenu des fichiers.husky - pre-commit hook exited with code 1 (error)Votre commit n'a jamais été créé : un hook — lint, tests, formateur — s'est terminé avec un code non nul et git a abandonné. La vraie raison n'est pas cette ligne mais la sortie du hook juste au-dessus, généralement une règle de lint ou une erreur de types. Corriger ce que le hook a signalé et committer à nouveau est la seule vraie réponse. git commit --no-verify saute tous les hooks de commit et produit bien un commit, mais il n'a pas passé la vérification : il a seulement déplacé l'échec vers la CI, et du code non formaté part tel quel chez vos collègues.

npm20

Avec npm, la cause tient dans la première ligne code XXXX et non dans les six dernières lignes npm ERR!, et quand la panne vient de l'arbre de dépendances ou d'une compilation native plutôt que de votre code, supprimer node_modules puis réinstaller en règle environ la moitié.

npm ERR! ERESOLVE unable to resolve dependency treeDepuis npm 7, les plages de peerDependencies sont imposées, et ce message dit que npm n'a trouvé aucun jeu de versions les satisfaisant toutes en même temps. C'est fréquent quand le paquet que vous installez a une plage de peer qui exclut la version de react ou de typescript déjà présente, surtout juste après une montée de version majeure. Lisez les lignes Found: et Could not resolve: pour voir qui exige quoi, puis déplacez l'un des deux vers une version compatible : c'est le vrai correctif. npm install --legacy-peer-deps installe en ignorant totalement les plages de peer, ce qui vous débloque mais laisse un arbre que les paquets n'ont jamais accepté ; les erreurs d'exécution dues aux versions désaccordées seront pour vous.npm ERR! Conflicting peer dependency: react@18.3.1Cette ligne isole la paire qui s'affronte réellement dans le rapport ERESOLVE : ce paquet exige cette version d'un peer alors que votre arbre en contient une autre. Cela signifie généralement que la bibliothèque hôte a fait un saut de version majeure et qu'un plugin qui l'utilise n'a pas suivi. Interroger par nom avec npm ls react affiche, sous forme d'arbre, qui a demandé quelle version, et l'on voit sur le champ lequel des deux doit bouger. Mettre le plugin à jour est le vrai correctif ; --force écrit malgré tout l'arbre désaccordé et cache le problème jusqu'à l'exécution.npm WARN react-dom@17.0.2 requires a peer of react@17.0.2 but none is installed.npm 6 se contentait d'avertir au sujet des dépendances peer et ne les installait jamais pour vous : le paquet est là, mais le compagnon dont il dit avoir besoin ne l'est pas. Le message apparaît dans un projet resté sur npm 6, ou quand vous utilisez un vieux lockfile de cette époque. Installez vous-même le peer nommé dans une version comprise dans la plage affichée, et c'est réglé. Rien n'a encore échoué puisqu'il ne s'agit que d'un avertissement, mais cela revient plus tard sous la forme d'un Cannot find module, ou de deux copies de la même bibliothèque produisant des erreurs incompréhensibles.npm WARN deprecated request@2.88.2: request has been deprecatedL'auteur du paquet a marqué cette version comme n'étant plus recommandée : elle s'est installée et fonctionne toujours. Ce n'est généralement pas quelque chose de votre package.json mais une dépendance transitive entraînée par un paquet que vous utilisez. Interroger par nom avec npm ls request montre laquelle de vos dépendances directes l'amène, et c'est là qu'il faut agir, pas sur ce paquet. Il n'y a rien à faire aujourd'hui : deprecated n'est pas une faille de sécurité, et c'est npm audit qui vous parle de celles-là.npm ERR! npm ci can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync.npm ci installe strictement ce que le lockfile enregistre, et il s'est arrêté avant de commencer parce que package.json demande quelque chose que le lockfile ne contient pas. Cela arrive quand quelqu'un a édité package.json à la main ou y a résolu un conflit sans lancer install, ou a committé package.json sans le lockfile à côté. Lancez npm install une fois en local pour que le lockfile corresponde, puis committez le lockfile : c'est tout le correctif. Supprimer package-lock.json pour passer outre réétablit au contraire toutes les dépendances vers des versions plus récentes et change en silence le contenu de votre build.npm ERR! The `npm ci` command can only install with an existing package-lock.json or npm-shrinkwrap.jsonnpm ci ne tourne pas du tout sans lockfile, car rien ne lui dit quelles versions installer. Cela arrive quand package-lock.json est dans .gitignore, n'a jamais été committé, ou quand le répertoire où vous vous trouvez n'est pas la racine du projet. npm install --package-lock-only écrit le lockfile sans rien installer, et le committer fait fonctionner la CI. Ne mettez jamais package-lock.json dans .gitignore : la garantie que la CI construise deux fois la même chose repose sur ce seul fichier.npm ERR! Invalid Version:Le champ version de package.json n'est pas un semver valide, donc npm ne peut pas analyser le paquet du tout. Cela arrive avec une valeur écrite à la main comme 1.0 ou v1.0.0 ou une chaîne vide, surtout après un conflit mal résolu dans ce fichier. npm pkg set version=1.0.0 réécrit une version correcte en trois parties. La commande ne modifie que package.json et ne touche ni node_modules ni le lockfile, de sorte que toute commande lisant le fichier refonctionne immédiatement ensuite.npm ERR! 404 Not Found - GET https://registry.npmjs.org/@acme/ui - Not foundLe registre n'a aucun paquet de ce nom — un 404 répond au sujet du nom, pas de votre réseau ni de vos identifiants. Cela arrive sur une faute de frappe, sur un paquet dépublié, ou sur un scope privé auquel vous n'êtes pas connecté. Un paquet privé ressemble exactement à un paquet inexistant pour qui n'y a pas accès, d'où ces trois cas réunis en une seule ligne. npm view @acme/ui version confirme si le nom existe publiquement ; pour un scope privé, vérifiez que .npmrc contient le registre et le jeton de ce scope. Les deux vérifications ne font que lire.npm ERR! request to https://registry.npmjs.org/express failed, reason: unable to verify the first certificateLa connexion TLS a échoué : la chaîne de certificats présentée par le serveur remonte à une autorité en laquelle node n'a pas confiance. Dans l'immense majorité des cas, c'est un réseau d'entreprise dont le proxy ouvre le trafic et le resigne avec son propre certificat ; parfois, c'est un serveur qui n'a pas envoyé son certificat intermédiaire. Apprendre à npm la racine de votre entreprise avec npm config set cafile est le correctif juste. strict-ssl false fait aussi disparaître cette ligne, mais désactive totalement la vérification des certificats, ce qui permet à quiconque sur le chemin de vous servir des paquets modifiés : ne l'utilisez pas.npm ERR! code EINTEGRITYLe hachage de l'archive téléchargée ne correspond pas à ce que le lockfile enregistre : npm a jugé qu'il ne pouvait pas faire confiance à ce qui est arrivé et s'est arrêté. C'est une entrée de cache corrompue, un proxy qui a modifié le téléchargement, ou plus rarement un lockfile dont la valeur integrity a été éditée à la main ou mal fusionnée. npm cache clean --force vide le cache local pour que l'installation suivante retélécharge ; il ne supprime que des copies en cache et se répète sans risque. Si cela persiste pour un seul paquet, c'est la valeur integrity enregistrée qui est fausse et cette entrée doit être réétablie avec npm install.npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules'npm a voulu écrire dans un répertoire système que votre utilisateur ne possède pas : le paquet n'a rien de mauvais, vous n'avez simplement pas le droit d'y écrire. C'est presque toujours un npm install -g visant un node que le gestionnaire de paquets du système a placé à un endroit comme /usr/local. npm config set prefix ~/.npm-global déplace les installations globales dans votre répertoire personnel et, son bin étant dans le PATH, l'erreur ne revient pas. sudo npm install -g fonctionne, mais laisse des fichiers appartenant à root dans le cache et dans node_modules, qui produiront plus tard le même EACCES lors d'installations ordinaires ; un gestionnaire de versions comme nvm supprime toute cette famille de problèmes.npm ERR! enoent ENOENT: no such file or directory, open '/home/me/package.json'npm a cherché package.json dans le répertoire courant puis en remontant et n'en a trouvé aucun : vous avez lancé une commande npm à un endroit qui n'est pas un projet. Cela arrive quand vous êtes à la racine d'un monorepo alors que le projet est dans un sous-dossier, quand vous êtes à côté du dossier cloné, ou quand vous avez simplement oublié le cd. La réponse est de vous déplacer dans le dossier qui contient package.json, et un ls est le plus rapide pour le voir. N'utilisez npm init -y que si vous voulez réellement démarrer un nouveau projet ici : dans le mauvais dossier, il laisse un package.json orphelin qui embrouillera l'outillage plus tard.npm ERR! code ELIFECYCLEUn script de package.json s'est terminé avec un code non nul — ELIFECYCLE est l'enveloppe que npm met autour, pas la cause. La cause est ce qu'a fait votre script de build ou de test, et les vraies lignes d'erreur se trouvent au-dessus de celle-ci. Remontez jusqu'à la première erreur, ou exécutez à la main la commande réelle affichée après npm ERR! <pkg>@<ver> <script>: pour voir sa sortie sans l'enveloppe de npm. Le code de sortie qui suit renseigne aussi un peu : 1 est un échec ordinaire, tandis que 137 signifie que le processus a été tué, typiquement pour cause de mémoire.gyp ERR! build errorUne dépendance contient du C ou du C++ à compiler sur votre machine au moment de l'installation, et cette compilation a échoué — node-gyp exige un compilateur et python. Cela arrive quand aucune chaîne de compilation n'est installée, ou quand le paquet est plus ancien que votre node et que les en-têtes ne correspondent plus. Installez la chaîne : xcode-select --install pour les outils en ligne de commande sous macOS, build-essential et python3 sous Debian ou Ubuntu, la charge de travail C++ de Visual Studio sous Windows. Si une version plus récente du paquet fournit un binaire précompilé pour votre node, mettre le paquet à jour est bien plus rapide que réparer l'environnement de compilation.Error: Cannot find module 'express'node n'a pu résoudre ce nom vers aucun fichier : il n'est pas dans node_modules, ou vous avez lancé depuis un répertoire sans node_modules. Cela arrive quand vous n'avez jamais installé, quand une installation a échoué à mi-chemin en laissant un arbre partiel, ou quand le paquet est en devDependencies et que vous avez installé avec --omit=dev. rm -rf node_modules && npm install reconstruit l'arbre depuis le lockfile ; c'est sans danger, rien n'est perdu et le seul coût est le temps de téléchargement. Mais si le nom entre guillemets est un chemin relatif commençant par ./, aucun paquet ne manque : c'est le chemin dans votre propre code qui est faux.Module not found: Error: Can't resolve './components/Button' in '/app/src'L'empaqueteur n'a pas trouvé ce fichier à ce chemin — il s'agit de votre propre import, pas d'un paquet. Cela arrive quand le chemin relatif est décalé d'un niveau, quand l'extension manque ou est fausse, ou quand la casse du nom de fichier diffère de l'import. Ce dernier cas est le plus vicieux : les systèmes de fichiers de macOS et de Windows ignorent la casse, donc cela marche chez vous et ne casse que sur la CI Linux. Faites un ls du répertoire et comparez avec l'import caractère par caractère, casse comprise. Si le nom est un paquet et non un chemin, installez-le ; dans les deux cas rien n'est supprimé.Error: error:0308010C:digital envelope routines::unsupportednode 17 est arrivé avec OpenSSL 3, qui a retiré des valeurs par défaut un vieil algorithme de hachage, et un outil qui le réclame encore s'écroule au cœur de cet appel. C'est presque toujours un vieux webpack 4, ou un outil qui en embarque un, tournant sur un node moderne. export NODE_OPTIONS=--openssl-legacy-provider réactive les algorithmes anciens pour ce processus et est sans danger pour un build. Mais cela maintient en vie un outil mort : passer à webpack 5, ou à la version actuelle de votre framework, supprime totalement le besoin de cette option.FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memoryLe tas de V8 a atteint son plafond et node a renoncé de lui-même : le système d'exploitation ne l'a pas tué, node a jugé qu'il ne pouvait plus croître et s'est arrêté. La cause est une grosse vérification de types ou un gros bundle, un build avec source maps sur un grand projet, ou du code qui fuit, par exemple en accumulant tout dans un tableau. export NODE_OPTIONS=--max-old-space-size=4096 relève le plafond à 4 Go et suffit souvent, mais la machine doit réellement disposer de cette mémoire ; si la limite d'un conteneur est plus basse, c'est le système qui tue le processus, ce qui apparaît en code de sortie 137. Si le nombre doit sans cesse grandir, la cause est une fuite et non la limite.npm WARN EBADENGINE Unsupported engineUn paquet déclare une plage engines pour node ou npm que votre environnement ne satisfait pas — npm se contente d'avertir et installe quand même. Cela arrive quand vous êtes sur un vieux node installé comme paquet système, ou quand le projet est passé à un node plus récent que celui de votre shell. Basculez node vers une version comprise dans la plage affichée avec votre gestionnaire de versions ; la référence est le .nvmrc du projet ou le champ engines de package.json. Ce n'est qu'un avertissement par défaut, mais avec engine-strict=true dans .npmrc la même condition devient une erreur qui interrompt l'installation.zsh: command not found: tscLe shell a parcouru le PATH et n'a trouvé aucun exécutable de ce nom — l'installation elle-même a très bien pu réussir. Cela arrive quand le répertoire bin global de npm n'est pas dans le PATH, quand vous avez installé en local plutôt qu'en global et que le binaire est allé dans node_modules/.bin, ou quand le shell garde un ancien PATH en cache. npx tsc --version exécute la copie locale sans toucher au PATH : cette seule ligne sépare « pas installé » de « pas dans le PATH ». Pour une installation réellement globale, ajoutez au PATH la sortie de npm prefix -g suivie de /bin, puis ouvrez un nouveau shell.

JavaScript15

Les erreurs du navigateur et de Node disent d'ordinaire ce qui a cassé et non pourquoi la valeur est devenue telle — vous avez lu undefined, ce n'était pas une fonction, ce n'était pas du JSON — l'endroit à corriger se trouve donc en amont de la ligne qui a levé l'erreur, et faire taire cette seule ligne avec ?. et des valeurs par défaut fait revenir le même problème plus loin, sous une forme plus difficile à reconnaître.

Uncaught TypeError: Cannot read properties of undefined (reading 'name')La valeur à gauche du point vaut undefined et vous en avez lu une propriété ; le nom entre parenthèses est la propriété voulue, donc c'est la valeur d'avant qui est cassée. Cela vient d'une réponse pas encore arrivée, d'une prop que personne n'a passée, d'un niveau de trop comme dans data.user.name, ou de arr[0].id sur un tableau vide. Là où la valeur est vraiment facultative, user?.name coupe court ; mais si elle devait être présente, ?. ne fait que transformer l'erreur en un undefined qui échoue à la ligne suivante : cherchez en amont pourquoi c'est undefined. Avant Chrome 78, la même erreur s'écrivait Cannot read property 'name' of undefined.TypeError: items.map is not a functionLe nom existe mais ce n'est pas une fonction — s'il n'existait pas du tout, le message parlerait d'undefined. Causes typiques : quelque chose que vous prenez pour un tableau et qui est en fait un objet ou une NodeList, une API qui renvoie {data: [...]} au lieu du tableau, ou une mauvaise forme d'export par défaut. Affichez-le avant de théoriser : un seul console.log(typeof items, items) règle la moitié des cas sur place. Une NodeList ou un Set n'a besoin que d'Array.from(items) ; mais si c'était {data: [...]}, l'envelopper est faux et items = res.data est la correction.RangeError: Maximum call stack size exceededLes appels se sont empilés plus profondément que ne l'autorise le moteur, et il s'agit d'ordinaire non d'une récursion profonde mais d'une récursion sans fin. Une fonction dont la condition d'arrêt manque ou n'est jamais atteinte, deux fonctions qui s'appellent l'une l'autre, JSON.stringify sur un objet qui se contient lui-même, ou en React un rendu qui modifie l'état dont il dépend. La pile dans la console répète deux ou trois cadres : cette paire est la boucle, et le cas de base y appartient. Si le calcul exige vraiment de la profondeur, réécrire la récursion en boucle ou en pile explicite est la seule voie : on ne relève pas la limite de pile d'un navigateur.SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSONCe que vous avez donné à JSON.parse était du HTML, pas du JSON. Le fragment <!DOCTYPE cité dans le message en est la preuve : le serveur a répondu par une page HTML — un 404, un 502 ou une redirection de connexion — donc le vrai bogue est en amont de l'analyse, dans la requête. Causes typiques : la mauvaise URL, un proxy de serveur de développement qui a servi index.html au lieu de l'API, ou une session expirée redirigée vers la page de connexion. Vérifiez res.ok avant d'appeler res.json(), et lisez res.text() pour voir ce qui est réellement arrivé ; appeler l'URL avec curl -s est le regard le plus rapide. Avant Chrome 111 et Node 20, la même erreur s'écrivait Unexpected token < in JSON at position 0.SyntaxError: Unexpected end of JSON inputL'analyseur a atteint la fin du document alors qu'il lisait encore du JSON, et presque toujours le corps était tout simplement vide. Appeler res.json() sur un 204 No Content ou sur une réponse d'erreur sans corps, lire deux fois le corps d'une réponse de sorte que la seconde revienne vide, ou lire un fichier tronqué en pleine écriture. Prenez d'abord le texte et vérifiez-le avant d'analyser — const t = await res.text(); if (!t) return null; — cela donne un diagnostic exact. Le masquer avec JSON.parse(text || 'null') fait passer une réponse vide pour normale : cherchez d'abord pourquoi le serveur a envoyé un corps vide.TypeError: Failed to fetchLa requête s'est terminée sans réponse, et le navigateur cache volontairement la raison : un blocage CORS, une adresse morte, un certificat invalide et une extension bloqueuse de publicité donnent exactement les deux mêmes mots. C'est une erreur levée et non un statut : un 404 ou un 500 n'arrive jamais jusqu'ici, le serveur n'a même pas commencé à répondre. Il y a souvent juste au-dessus, dans la console ou l'onglet Network, une seconde ligne plus précise : lisez-la d'abord. Appeler l'URL avec curl -i sépare « le serveur est à terre » de « le navigateur a refusé ». Firefox formule la même situation en NetworkError when attempting to fetch resource.Access to fetch at 'https://api.example.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.La requête a atteint le serveur et une réponse est revenue, mais cette réponse ne portait aucun en-tête autorisant cette origine : le navigateur a donc refusé de la remettre à votre JavaScript. Seuls les navigateurs appliquent cette règle, d'où le fait que la même URL fonctionne depuis curl — on croit le serveur en bon état et le navigateur seul fautif. Le correctif est toujours côté serveur : ajouter Access-Control-Allow-Origin: http://localhost:3000 à la réponse. Le front n'y peut rien, et si le serveur n'est pas le vôtre, passer l'appel par le vôtre est la seule voie. Allow-Origin: * ne vaut pas pour les requêtes qui envoient des cookies ; celles-ci exigent l'origine exacte et Allow-Credentials.SyntaxError: Cannot use import statement outside a moduleNode ou le navigateur a lu ce fichier comme un script CommonJS, et il contenait le mot-clé ESM import. Un fichier .js est du CommonJS sauf si package.json en décide autrement, et dans un navigateur la même chose survient quand la balise <script> n'a pas type="module". npm pkg set type=module déclare tout le paquet en ESM et règle le problème, mais dès cet instant chaque .js du paquet perd require et __dirname : les fichiers CommonJS restants doivent suivre — si vous ne voulez convertir qu'un fichier, le renommer en .mjs est le changement le plus étroit et le plus sûr.ReferenceError: require is not defined in ES module scope, you can use import insteadC'est le miroir exact de l'erreur précédente : le fichier est lu comme de l'ESM et il contient le require de CommonJS. Cela arrive presque toujours juste après l'ajout de "type": "module" dans package.json, alors que d'anciens scripts subsistent. Pour laisser ce fichier dans l'ancien monde, mv script.js script.cjs est la modification la plus étroite ; pour le faire migrer, réécrire require en import implique aussi de traiter __dirname et require.main === module, qui n'existent pas en ESM.Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/app/src/util' imported from /app/src/index.jsQuand Node exécute de l'ESM, il traite les chemins d'import comme des noms de fichiers littéraux, à la manière d'un navigateur : './util' n'est donc pas './util.js', c'est un fichier inexistant. CommonJS essayait les extensions à votre place, et TypeScript laisse les imports sans extension tels quels à la compilation — d'où la pile de ces erreurs au premier lancement avec node d'un projet bâti par tsc. Ajoutez l'extension .js aux imports relatifs ; dans un fichier TypeScript aussi on écrit './util.js', car ce que Node lira, c'est la sortie compilée. Les noms de paquets venant de node_modules ne prennent pas d'extension.ReferenceError: window is not definedLe code s'est exécuté dans Node côté serveur, pas dans un navigateur. Node n'a ni window, ni document, ni localStorage : toucher à window pendant le chargement d'un module dans un cadre qui rend d'abord côté serveur, comme Next.js ou Nuxt, s'arrête ici — souvent une seule ligne hors du composant, ou l'import même d'une bibliothèque réservée au navigateur. Si le travail est propre au navigateur, protégez-le par typeof window !== 'undefined' ou, mieux, déplacez-le dans useEffect, qui ne s'exécute que dans le navigateur. Quand toute une bibliothèque est réservée au navigateur, Next.js peut l'écarter du rendu serveur avec dynamic(() => import('./C'), { ssr: false }) — au prix de l'absence de cette partie dans le HTML rendu par le serveur.Hydration failed because the initial UI does not match what was rendered on the serverLe HTML envoyé par le serveur et ce que le navigateur a produit à son premier rendu diffèrent : React n'a pas pu rattacher l'un à l'autre. Utiliser new Date() ou Math.random() pendant le rendu, lire localStorage, ou dessiner selon la largeur de window garantit deux réponses différentes — de même qu'un balisage que le navigateur répare en silence, comme un <div> dans un <p>. La règle est de rendre au premier passage exactement ce que le serveur a rendu, puis de changer après l'exécution de useEffect ; le prix est que cette partie apparaît un instant plus tard et manque au HTML du serveur. React 19 formule la même situation en "the server rendered HTML didn't match the client" et affiche un diff de ce qui différait.Objects are not valid as a React child (found: object with keys {name, id})La valeur que vous avez demandé à React d'afficher est un objet et non une chaîne ou un nombre, et la liste de clés entre parenthèses dit de quel objet il s'agit. En général la ligne devrait être {user.name} là où elle dit {user}, ou vous avez tenté d'afficher une réponse entière. Si vous voyez found: [object Promise] au lieu d'une liste de clés, la cause diffère : vous avez affiché le résultat d'une fonction async sans l'attendre. La solution est de choisir le champ à montrer ; JSON.stringify(user) convient pour un coup d'œil en débogage, mais ne le laissez pas à l'écran.Each child in a list should have a unique "key" prop.Des éléments frères rendus en liste n'ont pas de key : React ne peut donc pas les apparier aux mêmes entrées au rendu suivant. Vous avez construit les éléments avec items.map(...) sans key ; ce n'est qu'un avertissement, l'affichage a bien lieu, mais il revient en bogue silencieux dès que la liste change — le symptôme est une valeur de champ ou une animation qui reste sur la mauvaise ligne. Donnez un id stable issu de vos données. Utiliser l'indice du tableau comme key n'est sûr que pour une liste dont l'ordre ne change jamais et où l'on n'insère ni ne supprime au milieu ; sinon cela reproduit presque exactement le problème de l'absence de key. Depuis React 19, le Warning: en tête a disparu.Too many re-renders. React limits the number of renders to prevent an infinite loop.Un rendu a modifié l'état, cet état a déclenché un autre rendu, et React a coupé la boucle pour éviter l'infini. C'est presque toujours une fonction appelée là où il fallait la passer : onClick={setOpen(true)} s'exécute à chaque rendu, il faut écrire onClick={() => setOpen(true)}. Les autres formes courantes sont la modification d'état directement dans le corps du rendu, et un useEffect dont la liste de dépendances contient la valeur qu'il met à jour. Déplacez les changements d'état dans un gestionnaire d'événement ou un useEffect, et si la valeur peut être calculée pendant le rendu, demandez-vous si elle doit être un état.

Python18

Une trace Python coupe la réponse en deux : la dernière ligne dit ce qui a échoué, les cadres au-dessus disent où — ne lire que la dernière ligne donne le nom et fait perdre l'endroit ; et pour les erreurs de valeur absente comme NoneType et KeyError, la cause siège presque toujours dans un cadre au-dessus de celui qui a planté.

ModuleNotFoundError: No module named 'requests'Python a parcouru tous les répertoires de sys.path et n'y a trouvé aucun module de ce nom. Soit il n'a jamais été installé, soit il l'a été pour un autre interpréteur : faire pip install en dehors d'un environnement virtuel puis exécuter à l'intérieur donne exactement cela. Écrit python -m pip install, il s'installe dans l'interpréteur réellement lancé, et le décalage disparaît.error: externally-managed-environmentCe Python appartient au système d'exploitation ou à Homebrew, et pip refuse d'y écrire (PEP 668). Vous avez lancé pip install sur l'interpréteur du système ; le message vous demande de créer un environnement virtuel. --break-system-packages fait ce que son nom annonce et peut laisser des fichiers gérés par apt en mauvais état : créez plutôt un .venv et installez dedans.ImportError: cannot import name 'User' from partially initialized module 'models' (most likely due to a circular import)Deux modules s'importent mutuellement : vous demandez donc un nom à un module chargé à moitié seulement. Cela vient d'une forme A importe B et B importe A, fréquente juste après avoir découpé un fichier, quand une annotation de type ramène l'import dans l'autre sens. Remplacez from y import Thing par import y et utilisez y.Thing dans la fonction : la résolution a lieu plus tard et le cycle cesse de gêner.IndentationError: unexpected indentLa ligne est indentée plus loin que la précédente, et rien au-dessus n'ouvre un bloc qui justifierait ce niveau. En général vous avez collé du code qui apportait ses propres espaces, ou supprimé une ligne if en laissant son corps indenté sous rien. Retirez l'espace en tête de la ligne signalée ; si la différence ne se voit pas, affichez cette ligne avec cat -A et les espaces et tabulations apparaissent.TabError: inconsistent use of tabs and spaces in indentationTabulations et espaces sont mélangés dans un même bloc, donc Python ne peut pas décider quelle ligne est plus profonde. Cela arrive en collant depuis un éditeur qui insère des tabulations, ou quand deux personnes modifient le même fichier avec des réglages différents ; à l'écran les lignes semblent identiques, vous ne le trouverez pas à l'œil. python -m tabnanny app.py affiche les numéros de ligne fautifs, et le reste consiste à convertir tout le fichier en quatre espaces dans l'éditeur.SyntaxError: invalid syntaxL'analyseur n'a pas pu former une instruction avec ce qu'il a trouvé là, et la cause se situe le plus souvent à la ligne précédant celle indiquée. Une parenthèse ou un guillemet non fermé, deux-points manquants, ou le print "x" de Python 2 sont les causes classiques : parenthèse ouverte, l'analyseur continue plusieurs lignes avant d'abandonner. python -m py_compile app.py vérifie la syntaxe sans rien exécuter, et depuis la 3.10 les messages sont bien plus précis, donc monter de version est déjà un diagnostic.TypeError: 'NoneType' object is not subscriptableLa valeur que vous avez indexée avec [...] vaut None. Quelque chose en amont a renvoyé None sans bruit : un dict.get() sur une clé absente, un re.match qui n'a pas correspondu, ou une fonction sans return sur le chemin emprunté. Plutôt que de vous protéger à l'endroit du plantage, remontez et cherchez pourquoi c'est None — un if qui saute le None déplace simplement la même erreur à la ligne suivante.AttributeError: 'NoneType' object has no attribute 'get'L'objet à gauche du point vaut None, donc l'attribut ou la méthode demandée n'existe pas. Même racine que nonetype-not-subscriptable, et cela survient surtout quand on enchaîne directement sur une fonction qui renvoie None en cas d'échec, comme find() de BeautifulSoup ou re.search(). Affichez d'abord ce que cette fonction cherchait, et si ne rien trouver est un cas normal, traitez cette branche explicitement.KeyError: 'name'La clé n'est pas dans le dict, et la chaîne entre guillemets est exactement la clé recherchée : commencez par là, car c'est en général une faute de frappe, une différence de casse, ou une réponse d'API dont la forme n'est pas celle que vous supposiez. Si la valeur est vraiment facultative, d.get("name") renvoie None et d.get("name", 0) fournit une valeur par défaut ; mais employer .get sur une valeur obligatoire échange l'erreur contre un None qui circule dans votre code et casse bien plus loin.IndexError: list index out of rangeVous avez demandé une position que la liste n'a pas. Pour une longueur n, le dernier indice valide est n-1, donc range(len(x) + 1) et x[len(x)] s'arrêtent toujours ici, et x[0] sur une liste vide donne la même erreur — fréquent quand un filtre ou un split au-dessus n'a rien laissé. Boucler avec for item in items: supprime purement cette classe de bogue, et si la position vous est vraiment nécessaire, enumerate(items) la fournit.ValueError: invalid literal for int() with base 10: '3.5'Vous avez donné à int() une chaîne qu'il ne peut pas lire comme entier, et le texte entre guillemets est cette chaîne. Un point décimal comme dans '3.5', une chaîne vide, une entrée terminée par un retour à la ligne ou un séparateur de milliers comme dans '1,000' sont les causes courantes. Pour un décimal, int(float(s)) passe en deux étapes, mais tronque la partie fractionnaire au lieu d'arrondir ; et pour toute valeur saisie par une personne, l'envelopper dans try/except ValueError est la vraie réponse.UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byteVous avez lu un fichier ou une suite d'octets comme de l'UTF-8 et rencontré un octet que l'UTF-8 interdit ; le message donne la position et l'octet. Le plus souvent le fichier est en cp1252 ou dans un autre encodage hérité de Windows, ou ce n'est pas du texte du tout : une image, un zip, ou des données gzip non décompressées. La bonne réponse est de trouver l'encodage réel et de le passer via encoding= ; errors="replace" laisse la lecture s'achever mais change ces octets en points d'interrogation, et la donnée poursuit son chemin silencieusement abîmée.ZeroDivisionError: division by zeroQuelque chose a été divisé par zéro — et en pratique le diviseur est rarement un zéro littéral, c'est un décompte qui a donné zéro. Un calcul de moyenne dont la liste s'est révélée vide, ou un filtre sans correspondance, en est la source classique : cela passe sur vos données de développement et échoue pour la première fois en production. Vérifiez le dénominateur avant de diviser et décidez de ce que zéro signifie ici ; renvoyer 0, renvoyer None ou laisser l'exception remonter sont trois décisions différentes, chacune juste dans certains cas.RecursionError: maximum recursion depth exceededUne fonction s'est appelée elle-même plus profondément que la limite par défaut de 1000 cadres. Bien plus souvent qu'un calcul réellement profond, cela signifie que la condition d'arrêt manque ou n'est jamais atteinte ; la récursion indirecte compte aussi, par exemple un __getattr__ ou une property qui relit son propre attribut. Repérez les deux ou trois cadres qui se répètent dans la trace et corrigez d'abord le cas de base. sys.setrecursionlimit() relève bien le plafond, mais vous laisse dépasser la vraie pile C, et Python meurt alors d'un coup au lieu de lever une exception : réécrire la récursion en boucle est la réponse sûre.UnboundLocalError: cannot access local variable 'count' where it is not associated with a valueSi une fonction affecte un nom n'importe où dans son corps, Python considère ce nom comme local à la fonction — et vous l'avez lu avant que l'affectation ne s'exécute. Cela survient quand vous attendiez la valeur extérieure du même nom, ou la première fois que vous écrivez une opération de lecture-écriture comme count += 1. L'initialiser dans la fonction avec count = 0 est la réponse habituelle ; s'il faut vraiment modifier la valeur au niveau du module, global count le fait, au prix d'une valeur dont les écrivains deviennent difficiles à suivre. Jusqu'à la 3.10 la même erreur s'écrivait 'local variable referenced before assignment'.TypeError: greet() takes 1 positional argument but 2 were givenVous avez passé un argument de plus que ce que la fonction accepte, et quand l'écart est exactement de un, c'est presque toujours self. Définissez une méthode dans une classe comme def greet(name): et l'appel obj.greet("x") envoie obj en premier argument, ce qui en fait deux. S'il s'agit d'une méthode, écrivez def greet(self, name): pour qu'elle reçoive self ; si elle n'a pas besoin de l'instance, marquez-la @staticmethod.PermissionError: [Errno 13] Permission deniedLe système d'exploitation a refusé cette opération sur ce chemin. Vous écriviez dans un endroit appartenant à un autre, comme /var/log ou /usr, ou dans un volume monté d'un conteneur dont l'UID ne correspond pas à l'utilisateur du conteneur, ou — le cas oublié — vous n'avez pas le droit d'écriture sur le répertoire et non sur le fichier, ce qu'exige la création d'un nouveau fichier. Vérifiez d'abord propriétaire et mode avec ls -ld, et avant de recourir à sudo, envisagez de déplacer le chemin là où vous pouvez écrire : un fichier créé sous sudo redonnera la même erreur la fois suivante sans sudo.OSError: [Errno 98] Address already in useLe bind a échoué parce qu'un autre processus détient déjà ce port. Soit le serveur précédent n'est pas complètement mort, soit un rechargeur automatique a lancé deux copies, soit un conteneur Docker publie déjà le même port. lsof -i :8000 donne le PID qui le détient, pour ne nettoyer que celui-là — lisez le nom du processus avant de faire kill -9 sur quoi que ce soit. L'errno varie selon le système : Linux affiche 98 ici, macOS affiche 48.

Build et types10

Les erreurs de build sont un outil qui refuse avant toute exécution : elles ne cassent rien à l'instant où elles surgissent, mais elles posent deux questions — corrigerez-vous le type ou le chemin pour coller à la forme réelle, ou ferez-vous passer cette seule ligne avec un as any ou un commentaire de suppression ? Et c'est ici que se révèlent pour la première fois les choses qui ne sont vraies que sur votre machine : la casse, les extensions et les variables d'environnement.

error TS2307: Cannot find module 'lodash' or its corresponding type declarations.tsc n'a trouvé ni le module lui-même ni aucune déclaration de types pour lui, et il importe que le message dise les deux : le paquet peut manquer complètement, ou être installé sans types. S'il est installé, ce sont les types qui manquent : npm i -D @types/lodash ajoute le paquet compagnon, sachant que beaucoup de paquets récents embarquent leurs propres types et n'ont pas de @types. Si cela survient sur un import relatif, regardez la casse et les paths de tsconfig — un chemin vers vos propres fichiers n'a rien à voir avec @types.error TS2339: Property 'user' does not exist on type 'Request'.Ce type ne déclare pas cette propriété. Cela vient d'un champ que le type de la bibliothèque n'a pas (accrocher user au Request d'Express est le classique), d'une coquille, ou de la lecture d'une propriété présente sur un seul membre d'une union non affinée. Corriger le type pour coller à la forme réelle est la réponse ; pour une union, affiner avec 'x' in y ou un champ discriminant ouvre l'accès dans la branche. Le faire taire par as any ne bâillonne que le compilateur : cet endroit acceptera désormais aussi un nom de propriété mal orthographié.error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.Le type accepté par la fonction et le type passé diffèrent, et le message les énonce dans l'ordre : d'abord ce que vous avez donné, ensuite ce qu'elle voulait. Le cas de loin le plus fréquent est une valeur venant d'un champ de formulaire, d'une chaîne de requête d'URL ou de JSON, qui arrive en chaîne là où un nombre est attendu. Convertir une fois à la frontière est la réponse, mais Number(value) renvoie NaN au lieu de lever une erreur en cas d'échec : il faut donc empêcher ce NaN de circuler, et Number.isFinite(n) est la vérification adéquate.error TS18048: 'user' is possibly 'undefined'.La valeur peut être undefined et vous n'avez pas traité cette possibilité ; c'est tsc qui attrape pour vous un futur Cannot read properties of undefined. Cela apparaît sur des champs optionnels, sur le résultat d'un find() de tableau et sur des variables d'environnement peut-être absentes. La solution est de décider ce qui se passe en cas d'absence : coupez tôt avec if (!user) return null, ou court-circuitez avec user?.name. Le faire taire par user!.name est une déclaration de garantie — et quand la garantie est fausse, cela revient en exception à l'exécution, sans rien du filet qu'une vérification aurait laissé.error TS7006: Parameter 'req' implicitly has an 'any' type.Le paramètre n'a pas de type écrit et tsc n'avait rien pour l'inférer : il est donc devenu any implicitement, ce que noImplicitAny traite comme une erreur. Cela apparaît dans les fichiers repris de JavaScript et quand un callback est extrait dans sa propre variable ; à l'inverse, un callback écrit en ligne comme items.map(x => ...) a du contexte, tsc l'infère et cela ne se déclenche jamais. Écrire le type à cet endroit est la correction. Vous pouvez aussi écrire any explicitement, mais c'est décider de couper la vérification pour ce paramètre entièrement — quand on ne sait pas ce que c'est, unknown est plus honnête et force à affiner avant usage.Parsing error: Unexpected tokenESLint s'est arrêté à la lecture de la syntaxe, avant d'appliquer la moindre règle au fichier. Bien plus souvent qu'un code réellement cassé, cela signifie que l'analyseur ne connaît pas cette syntaxe : un fichier TypeScript lu par l'analyseur par défaut, du JSX jamais activé, ou des décorateurs et une syntaxe très récente confiés à un vieil analyseur. Lancer npx eslint --print-config app.ts sur ce fichier précis affiche quel parser et quelles parserOptions s'appliquent vraiment : commencez par là plutôt que de deviner. TypeScript exige @typescript-eslint/parser, et si le fichier ne doit pas être analysé du tout, le placer dans ignores est la bonne réponse.You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.C'est la ligne que webpack ajoute après Module parse failed : il a tenté de lire ce fichier comme du JavaScript et ce n'en était pas. Soit vous avez importé quelque chose qui exige une transformation — TypeScript, JSX, CSS, une image, un fichier .vue — sans règle dans module.rules, soit un paquet de node_modules livre des sources non compilées alors que ce dossier figure dans votre exclude. Ajouter une règle de loader pour cette extension dans module.rules est la correction, et le chemin imprimé au-dessus du message indique le fichier qui a bloqué. Supprimer exclude: /node_modules/ pour faire disparaître l'erreur ralentit nettement tout le build ; n'excepter que ce paquet est le meilleur compromis.Failed to resolve import "./utils" from "src/main.ts". Does the file exist?Rien n'a été trouvé à ce chemin, et le « Does the file exist? » affiché désigne les trois choses vraiment à vérifier : la casse, l'extension, et tout alias dans tsconfig ou vite.config. Les systèmes de fichiers de macOS et de Windows ignorent la casse, donc ./Utils marche sur votre machine et casse pour la première fois en CI ou au déploiement, là où Linux la respecte — cette erreur est l'identité la plus courante du « pourtant ça marche chez moi ». git ls-files src | grep -i utils montre l'orthographe réellement présente dans le dépôt. Pour un alias comme @/utils, resolve.alias de vite.config et paths de tsconfig doivent concorder ; n'en corriger qu'un laisse l'éditeur muet alors que le build continue d'échouer.You're importing a component that needs useState. This React hook only works in a client component.Dans l'App Router, chaque composant est un composant serveur par défaut, et un composant serveur a importé un fichier qui utilise un hook n'ayant de sens que dans un navigateur, comme useState. La directive est une seule ligne 'use client' tout en haut du fichier ; l'ajouter entraîne ce fichier et tout ce qu'il importe dans le paquet client — d'où l'intérêt de marquer le plus petit morceau qui a besoin d'état plutôt que la page entière. Dans l'autre sens, découper pour qu'un composant client reçoive des composants serveur comme enfants garde la récupération des données sur le serveur. Next.js 13 formulait la même situation en "It only works in a Client Component but none of its parents are marked with \"use client\"".The engine "node" is incompatible with this module. Expected version ">=20"Le paquet que vous installez déclare dans le champ engines les versions de Node dont il a besoin, et la vôtre sort de cette plage. Le Expected et le Got qui suivent mettent l'exigence et votre version côte à côte : ces deux lignes suffisent — et si cela n'arrive qu'en CI, sa version de Node diffère de celle de votre machine. Monter de version avec nvm install 20 && nvm use 20 est la réponse directe, et inscrire la même version dans .nvmrc et la configuration CI les empêche de divergier à nouveau. Le --ignore-engines de yarn permet de passer outre, mais il supprime l'avertissement sans créer la compatibilité : si le paquet emploie une syntaxe plus récente, il échouera à l'exécution sur une erreur de syntaxe. npm signale la même situation par un avertissement EBADENGINE et ne bloque pas l'installation par défaut.

Docker12

Les erreurs de Docker ne deviennent lisibles qu'une fois rangées par couche — le client qui n'atteint pas le démon, le registre qui refuse, un RUN qui échoue au build, un conteneur qui meurt dès son démarrage sont quatre problèmes distincts — et pour les couches build et exécution, la ligne n'est pas la raison : la raison est dans la sortie de la commande qui tournait à l'intérieur, tandis que le coût de chaque correctif varie aussi selon la couche.

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?La commande docker ne fait rien elle-même : elle s'adresse à un démon via ce socket, et personne n'a répondu. Soit le démon ne tourne pas, soit Docker Desktop n'a pas fini de démarrer sous macOS ou Windows, soit sous Linux votre utilisateur n'est pas dans le groupe docker et ne peut pas ouvrir le socket ; les trois donnent cette même ligne. Sous Linux, lancez sudo systemctl start docker ; avec Desktop, ouvrez d'abord l'application. Si c'est une question de droits, sudo usermod -aG docker $USER puis une nouvelle session règlent l'affaire — sachez que ce groupe équivaut en pratique à root.Bind for 0.0.0.0:8080 failed: port is already allocatedVous avez réclamé ce port de l'hôte avec -p, et un autre conteneur ou processus le détient déjà. Le plus souvent un conteneur lancé plus tôt sans --rm est encore là, arrêté ou en marche, ou compose retient encore un conteneur plus ancien. docker ps --filter publish=8080 désigne directement le conteneur qui le publie ; s'il s'agit en fait d'un programme ordinaire de l'hôte, lsof -i :8080 le trouve. Ne changer que le côté hôte, comme -p 8081:80, vous débloque, mais laisser l'ancien conteneur en place, c'est la même collision la prochaine fois.Conflict. The container name "/api" is already in use by containerLe nom passé avec --name appartient déjà à un autre conteneur. Les noms sont uniques y compris parmi les conteneurs arrêtés, pas seulement ceux qui tournent : le plus souvent, un conteneur mort hier le retient encore — invisible dans docker ps, visible seulement dans docker ps -a. docker rm -f api libère le nom, et détruit du même coup la couche inscriptible de ce conteneur (les volumes nommés survivent). Pour un conteneur jetable, le lancer avec docker run --rm évite complètement la situation.failed to register layer: Error processing tar file(exit status 1): no space left on deviceIl n'y a plus de place sur le disque pour déballer la couche d'image. En général le projet n'est pas gros : c'est Docker qui conserve encore des mois d'images anciennes, du cache de build et des volumes de conteneurs supprimés. docker system df montre ce que pèsent images, conteneurs, volumes et cache de build, et ce qui est récupérable : lisez-le avant de supprimer quoi que ce soit. docker system prune enlève les conteneurs arrêtés, les images orphelines, les réseaux inutilisés et le cache de build — le build suivant est nettement plus lent sans ce cache — et ajouter --volumes supprime en plus les volumes rattachés à aucun conteneur, c'est-à-dire précisément là où l'on perd ses bases de données.pull access denied for myapp, repository does not exist or may require 'docker login'Le registre n'a pas voulu vous montrer ce dépôt, et le point clé est que le message couvre deux causes à la fois : le nom n'existe pas, ou il existe et vous n'avez pas le droit de le voir. Soit vous n'êtes pas authentifié pour un dépôt privé, soit le nom manque son utilisateur ou son organisation (myapp et myorg/myapp sont deux dépôts distincts), soit le nom est simplement faux. Pour une image privée, faites docker login sur ce registre ; si elle est censée être publique, relisez l'orthographe. Les registres ne distinguent volontairement pas « absent » de « interdit », car l'existence d'un nom est déjà une information.manifest for myapp:v2 not found: manifest unknownLe dépôt a été trouvé, mais l'étiquette n'y est pas. Contrairement à pull access denied, ce message indique que le nom était bon : il ne reste donc que l'étiquette à vérifier — une étiquette supprimée ou déplacée, un pipeline qui a poussé latest sans jamais créer v2, ou une étiquette sans image pour votre architecture. docker manifest inspect myapp:v2 confirme si l'étiquette se résout et quelles plateformes elle contient. Passer à latest pour avancer coûte un build non reproductible : corrigez plutôt l'étiquette.unauthorized: incorrect username or passwordLe registre a refusé les identifiants envoyés. Plus souvent qu'un mot de passe mal tapé, il s'agit d'un mot de passe envoyé à un registre qui n'accepte plus du tout les mots de passe de compte : Docker Hub n'accepte que des jetons d'accès dès que la double authentification est active, et les registres de GitHub et GitLab n'ont jamais voulu qu'un jeton ou une clé de déploiement. docker logout efface l'identifiant stocké, puis refaites docker login avec un jeton. En le passant par echo $TOKEN | docker login -u user --password-stdin, le jeton ne reste pas dans l'historique du shell.failed to solve: process "/bin/sh -c npm ci" did not complete successfully: exit code: 1Cette ligne RUN de votre Dockerfile s'est terminée avec un état non nul. Cette ligne ne dit que quelle commande a échoué et avec quel code ; la vraie raison se trouve dans la sortie de cette commande, au-dessus, que BuildKit replie souvent dès qu'une étape s'achève. Relancer avec docker build --progress=plain affiche intégralement la sortie de chaque étape, et si une couche en cache masque un échec plus ancien, ajoutez --no-cache — au prix d'une reconstruction depuis la première étape. exit code: 1 n'est pas une raison, seulement le fait que la commande a échoué.COPY failed: file not found in build context or excluded by .dockerignoreCOPY ne peut prendre que des fichiers situés dans le contexte de build, et le fichier n'y est pas. Le contexte est le dernier argument de docker build : le plus souvent vous avez visé un dossier parent avec ../x, ou .dockerignore a filtré le fichier — classique quand node_modules ou *.env est ignoré puis qu'on copie quelque chose de son contenu. Le message cite les deux causes : lisez d'abord cat .dockerignore, puis réécrivez le chemin depuis la racine du contexte. Élargir le contexte pour s'en sortir revient à envoyer tout le dossier au démon, et chaque build ralentit.exec /usr/local/bin/entrypoint.sh: exec format errorLe noyau n'a pas reconnu l'en-tête de cet exécutable, et de nos jours c'est presque toujours un décalage d'architecture : une image arm64 construite sur Apple Silicon exécutée sur un hôte amd64, ou l'inverse. Un script shell dépourvu de sa première ligne #!/bin/sh donne le même texte. Construire avec docker build --platform=linux/amd64 est la réponse courante, mais elle ne supprime pas le décalage : elle le masque par émulation, et tout ce qui passe par QEMU est plusieurs fois plus lent que du natif. Pour une image que vous garderez, construire les deux architectures avec buildx est la voie sans coût à l'exécution.standard_init_linux.go: exec user process caused: no such file or directoryLe conteneur a voulu lancer son point d'entrée et le noyau a répondu « no such file » — et le piège, c'est que le fichier est bel et bien là. Les fins de ligne du script sont en CRLF : la première ligne se lit donc #!/bin/sh\r et le noyau cherche un interpréteur littéralement nommé sh\r ; un clone sous Windows ou l'autocrlf de git activé produit exactement cela. dos2unix entrypoint.sh convertit ce fichier (ou sed -i 's/\r$//' entrypoint.sh à défaut), et une ligne *.sh text eol=lf dans .gitattributes empêche le retour. Nommer dans le #! un interpréteur absent de l'image — bash dans une image alpine — donne le même texte.OCI runtime create failed: exec: "bash": executable file not found in $PATH: unknownLe conteneur a bien été créé, mais le programme que vous lui demandiez d'exécuter n'était pas dans son $PATH. Les images basées sur Alpine fournissent sh et pas bash : docker run -it myapp bash ou un CMD ["bash", ...] finit donc exactement sur cette erreur — comme tout outil que vous croyiez dans l'image alors qu'il n'existe que sur votre hôte. docker run --rm -it myapp sh vous donne un shell pour voir ce que l'image contient vraiment. S'il vous faut réellement bash, RUN apk add --no-cache bash dans le Dockerfile l'ajoute, au prix d'une image plus grosse.

Lire un message d’erreur

  • Lisez à partir de la première ligne. Plus on descend, plus il s’agit des entrailles de l’outil ; la cause est généralement en haut.
  • S’il y a un fichier et un numéro de ligne, commencez là — pas la première image de la pile, mais la ligne la plus haute qui nomme un fichier de vous.
  • Cherchez le message tel quel, mais retirez d’abord vos chemins et vos noms de variables : c’est cela qui empêche la correspondance.
  • La même situation se formule autrement selon la version de l’outil. Si les résultats sonnent faux, ajoutez le numéro de version.
  • Avant de coller un correctif, vérifiez ce qu’il jette. Certains sont irréversibles.

Questions fréquentes

Q. Pourquoi ne pas traduire les messages ?

Parce qu’on va les chercher. L’outil écrit en anglais, et un message traduit ne trouve rien. Seuls le sens et le remède suivent la langue.

Q. Sur mon écran, la formulation diffère un peu.

Les outils reformulent d’une version à l’autre. Si le squelette correspond après avoir retiré vos chemins et vos noms, c’est la même erreur. Si la version diffère, ajoutez-la à la requête.

Q. Puis-je exécuter le correctif tel quel ?

Vérifiez d’abord ce qu’il jette. git reset --hard, un push forcé et docker system prune retirent des choses irrécupérables ; les fiches le disent quand c’est le cas.

Q. Comment chercher une erreur absente d’ici ?

Retirez du message vos chemins, noms et nombres, et cherchez le reste. Ce reste est la phrase écrite par les auteurs de l’outil : c’est elle qui correspond.