Corriger l'erreur Java « Unsupported class file major version »
Le nombre dans l'erreur dit tout : 52 correspond à Java 8, 55 à Java 11, 61 à Java 17 et 65 à Java 21. Voici comment savoir quel Java tourne vraiment et comment activer la bonne version.
Vous lancez un serveur Minecraft, un plugin ou un outil de build, et au lieu du démarrage attendu, le terminal affiche un nombre qui ne veut rien dire au premier abord : class file version 65.0. La bonne nouvelle, c'est que ce nombre contient déjà tout le diagnostic. Il suffit de savoir le lire. Cet article montre comment déduire de ce nombre la version de Java nécessaire, comment savoir quel Java tourne réellement sur votre serveur (ce n'est souvent pas celui que vous croyez) et comment activer durablement la bonne version.
Deux messages d'erreur différents, deux causes différentes
Le libellé exact est décisif, car les deux messages courants cachent des problèmes exactement opposés. Le premier vient de la machine virtuelle Java elle-même :
Error: LinkageError occurred while loading main class net.minecraft.bundler.Main
java.lang.UnsupportedClassVersionError: net/minecraft/bundler/Main has been compiled
by a more recent version of the Java Runtime (class file version 65.0), this version
of the Java Runtime only recognizes class file versions up to 61.0
Ce message signifie toujours la même chose : l'application a été compilée avec un Java plus récent que celui que vous avez installé. Le premier nombre est celui qu'apporte l'application, le second est celui que comprend votre environnement d'exécution. Dans l'exemple ci-dessus, le logiciel réclame Java 21, alors que Java 17 est installé.
La seconde variante lui ressemble, mais vient d'ailleurs :
java.lang.IllegalArgumentException: Unsupported class file major version 65
Cette forme courte n'est pas levée par la JVM, mais par une bibliothèque qui lit et analyse le bytecode, en règle générale ASM. Elle apparaît avec Gradle, avec de vieux chargeurs de plugins et avec des noyaux de serveur plus anciens. Ici, la situation est le plus souvent inversée : votre Java est trop récent pour le logiciel qui veut lire le bytecode. Confondre ces deux messages revient à installer dans la mauvaise direction, puis à s'étonner que l'erreur persiste. Retenez cette règle simple : si vous voyez la longue phrase avec has been compiled by a more recent version, il vous faut un Java plus récent. Si vous ne voyez que la phrase courte, il vous en faut probablement un plus ancien.
Décoder le nombre : version majeure moins 44
La conversion est plus simple que ne le laissent croire la plupart des tutoriels. La version majeure du fichier class moins 44 donne la version de Java. 65 moins 44 égale 21, c'est tout. La règle s'applique sans aucune exception depuis Java 1.1 et ne changera pas à l'avenir, car chaque nouvelle version majeure de Java augmente ce nombre d'exactement un.
| Class file version | Version de Java | Où on la rencontre |
|---|---|---|
| 52 | Java 8 | Minecraft jusqu'à 1.16.5, anciens modpacks Forge, logiciels d'entreprise plus anciens |
| 53 | Java 9 | rare, version de transition |
| 55 | Java 11 | beaucoup de bibliothèques, anciennes applications Spring |
| 60 | Java 16 | Minecraft 1.17.x |
| 61 | Java 17 | Minecraft 1.18 à 1.20.4, très nombreux plugins actuels |
| 65 | Java 21 | Minecraft à partir de 1.20.5, donc toute la série 1.21, noyaux de serveur modernes |
| 69 | Java 25 | builds tout récents, version LTS actuelle |
Les valeurs intermédiaires suivent la même règle : 62 correspond à Java 18, 63 à Java 19, 64 à Java 20, 66 à Java 22, et ainsi de suite. Le .0 derrière le nombre est la version mineure et n'a pratiquement jamais la moindre importance.
Ce que cela signifie concrètement pour Minecraft
La correspondance pour les serveurs Minecraft est sans ambiguïté et s'apprend par cœur. Jusqu'à 1.16.5 incluse, c'est Java 8, pour 1.17.x au minimum Java 16, de 1.18 à 1.20.4 au minimum Java 17, et à partir de 1.20.5 (donc pour toute la série 1.21) Java 21. Si class file version 65.0 apparaît dans le log alors que vous venez de mettre à jour vers une version récente, la cause est trouvée avant même d'avoir ouvert la configuration.
Quel Java tourne vraiment ?
L'erreur de raisonnement la plus fréquente avec cette classe de problèmes consiste à supposer que la sortie de java -version dans votre session SSH vaut aussi pour le service en cours d'exécution. C'est souvent faux. Commencez quand même par là :
java -version
La première ligne de la sortie indique la version, par exemple openjdk version "21.0.11" 2026-04-15. Si vous obtenez à la place bash: java: command not found, c'est qu'aucun Java ne se trouve dans le chemin de recherche, et que l'application est lancée par un script de démarrage avec un chemin absolu. Regardez alors quels environnements d'exécution sont installés :
ls /usr/lib/jvm
readlink -f "$(command -v java)"
update-alternatives --display java
readlink -f résout la chaîne de liens symboliques et vous montre le binaire réellement exécuté, par exemple /usr/lib/jvm/java-17-openjdk-amd64/bin/java. C'est plus important que le seul numéro de version, car vous aurez besoin de ce chemin par la suite.
La ligne du milieu utilise volontairement command -v et non le plus répandu which. which est un programme à part entière, et il n'est pas inclus dans l'installation minimale d'AlmaLinux 9 et 10, de Rocky Linux 9 et d'Oracle Linux 9. La variante avec which y échoue deux fois : d'abord which: command not found, puis readlink: missing operand. command -v est intégré au shell lui-même et fonctionne partout.
Pour un processus déjà en cours, il existe une méthode qui ne laisse aucun doute. Elle répond à la question de savoir avec quel Java le service a réellement démarré, indépendamment du chemin de recherche et des variables d'environnement :
ls -l /proc/$(pgrep -f server.jar | head -n 1)/exe
Le lien symbolique exe pointe vers le fichier exécutable du processus. Si le chemin affiché n'est pas celui attendu, vous tenez la cause : le service démarre avec un autre Java que votre shell. Cela arrive régulièrement avec les units systemd, car elles apportent leur propre environnement minimal et votre JAVA_HOME défini dans le .bashrc n'y existe tout simplement pas.
Lire la version de classe directement dans le fichier JAR
Parfois, vous voulez savoir quel Java un fichier exige avant même de le lancer. C'est possible sans installer d'outil supplémentaire. Chaque fichier .class commence par la signature CAFEBABE, suivie de deux octets de version mineure et de deux octets de version majeure. Le huitième octet est donc le nombre recherché :
unzip -p server.jar net/minecraft/bundler/Main.class | od -An -tu1 -N8
La sortie ressemble alors à 202 254 186 190 0 0 0 65. Les quatre premiers nombres sont la signature, le dernier est votre réponse : 65, donc Java 21. Pour d'autres programmes, remplacez le chemin de classe en conséquence ; le nom correct est fourni par unzip -l server.jar ou par l'entrée Main-Class dans META-INF/MANIFEST.MF. Si un JDK est installé, il existe plus confortable :
javap -verbose -cp server.jar net.minecraft.bundler.Main | grep major
Pour les plugins, cette astuce est particulièrement utile. Si un seul plugin interrompt le démarrage du serveur, vérifiez sa classe principale et vous saurez immédiatement si le plugin est trop récent pour votre noyau de serveur, ou l'inverse.
Installer la version de Java qui convient
C'est ici que les distributions se séparent nettement, et c'est exactement là que les tutoriels génériques échouent. Voici l'état des lieux relevé sur de vrais systèmes, vérifié en juillet 2026 :
| Paquet | Debian 13 | Debian 12 | Ubuntu 24.04 | Ubuntu 22.04 |
|---|---|---|---|---|
| openjdk-8-jre-headless | absent | absent | 8u492 | 8u492 |
| openjdk-11-jre-headless | absent | absent | 11.0.31 | 11.0.31 |
| openjdk-17-jre-headless | absent | 17.0.19 | 17.0.19 | 17.0.19 |
| openjdk-21-jre-headless | 21.0.11 | absent | 21.0.11 | 21.0.11 |
| openjdk-25-jre-headless | 25.0.3 | absent | 25.0.3 | 25.0.3 |
Lisez ce tableau une fois calmement, il vous fera gagner beaucoup de temps. Debian 12 ne connaît que Java 17, Debian 13 ne connaît plus Java 17, mais seulement 21 et 25. Si vous voulez donc faire tourner un serveur Minecraft 1.21 sur Debian 12, ou un programme en class file version 61.0 sur Debian 13, vous ne trouverez rien qui convienne dans les dépôts standard. Ubuntu se montre plus généreux sur ce point et livre tout, de Java 8 à Java 25, depuis une seule source.
Avant d'installer, vérifiez que le paquet est bien disponible :
apt update
apt-cache policy openjdk-21-jre-headless
Si la ligne Candidat, ou Candidate sur un système anglophone, affiche (aucun), le paquet n'existe pas dans votre version. Sinon, installez-le. Pour une simple exécution, la JRE suffit ; le paquet -headless évite les dépendances graphiques et constitue toujours le bon choix sur un serveur :
apt install -y openjdk-21-jre-headless
Si vous compilez vous-même ou si vous utilisez Gradle ou Maven, il vous faut le JDK et non la JRE, donc openjdk-21-jdk-headless. Nos articles sur Java 17 sur Debian et Java 21 sur Debian décrivent des méthodes plus détaillées.
Quand la distribution ne propose pas la version : Adoptium Temurin
Pour tous les cas que les dépôts standard ne couvrent pas, il existe le dépôt d'Adoptium. Il fournit Temurin 8 à 26 pour Debian 12, Debian 13, Ubuntu 22.04 et Ubuntu 24.04, et constitue donc la seule solution qui mette à disposition, sur chacun de ces systèmes, toutes les versions dont vous pouvez avoir besoin. Important : la méthode autrefois courante via apt-key est abandonnée, la clé se place aujourd'hui dans /etc/apt/keyrings/ et se voit rattachée par signed-by à ce dépôt précis.
apt install -y wget gpg apt-transport-https
mkdir -p /etc/apt/keyrings
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor | tee /etc/apt/keyrings/adoptium.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list
apt update
apt install -y temurin-21-jdk
L'appel à awk insère automatiquement le bon nom de code, à savoir trixie, bookworm, noble ou jammy. Si apt update s'interrompt ensuite avec Conflicting values set for option Signed-By, c'est qu'un ancien dépôt Adoptium existe déjà, créé le plus souvent via extrepo. Cherchez-le dans /etc/apt/sources.list.d/ et supprimez le fichier en double.
AlmaLinux, Rocky Linux et RHEL
Dans la famille Red Hat, les paquets portent d'autres noms et affichent la version sans le préfixe openjdk au début :
dnf install -y java-21-openjdk-headless
AlmaLinux 9, Rocky Linux 9 et Oracle Linux 9 proposent la série complète, de java-1.8.0-openjdk-headless jusqu'à java-25-openjdk-headless. AlmaLinux 10 a en revanche opéré la même coupure que Debian 13 et ne connaît plus que 21 et 25 ; un dnf install java-17-openjdk-headless s'y termine par No match for argument.
L'outil de bascule s'appelle ici simplement alternatives, et update-alternatives n'en est qu'un lien symbolique. Son comportement n'est pourtant pas identique : alternatives --list n'accepte aucun argument. Le update-alternatives --list java habituel sous Debian n'y affiche que le texte d'aide et se termine avec le code de retour 2. Utilisez alternatives --list | grep java ou alternatives --display java ; ce dernier signale alors java - status is auto. au lieu de la forme Debian java - auto mode.
Dans la famille Red Hat, les chemins d'installation portent la version complète du paquet dans le nom du répertoire, par exemple /usr/lib/jvm/java-21-openjdk-21.0.11.0.10-1.el9.x86_64, et non la forme courte de Debian avec suffixe d'architecture. Seul AlmaLinux 10 crée en plus le lien symbolique court java-21-openjdk. Ne recopiez donc pas ce chemin de mémoire, récupérez-le dans alternatives --display java.
Un comportement particulièrement vicieux ici : après l'installation de Java 17 à côté d'un Java 21 déjà présent, alternatives a basculé de lui-même le lien /usr/bin/java sur AlmaLinux 9 vers la version 17, donc la plus ancienne. Installer une seconde version uniquement pour l'utiliser de façon ciblée avec une vieille application modifie donc sans le vouloir le Java par défaut de tout le système. Après chaque installation supplémentaire, définissez explicitement alternatives --set java <chemin> et vérifiez avec java -version.
Activer réellement la bonne version
Installé ne veut pas dire actif. Après l'installation d'un second JDK, java -version affiche souvent encore l'ancienne version, car le lien symbolique /usr/bin/java reste inchangé. Sur Debian et Ubuntu, c'est le mécanisme des alternatives qui règle cela :
update-alternatives --list java
update-alternatives --config java
La seconde commande affiche une liste numérotée et vous demande votre choix. Ensuite, la sélection passe en manual et n'est plus écrasée par les futures installations de paquets, ce qui est exactement l'effet recherché. Pour scripter cela sans question interactive, utilisez la variante set avec le chemin complet :
update-alternatives --set java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java
Définissez en plus JAVA_HOME si des outils de build entrent en jeu. Gradle et Maven ignorent le lien symbolique et se fient à cette variable :
export JAVA_HOME=/usr/lib/jvm/temurin-21-jdk-amd64
$JAVA_HOME/bin/java -version
Notez qu'un export ne vaut que pour la session en cours. Pour les services, cela n'aide pas du tout : au prochain redémarrage, le service reprend l'ancienne version de Java, parce qu'il n'a jamais vu la variable. De façon durable, JAVA_HOME a donc sa place dans l'unit systemd sous forme de Environment= ou, à l'échelle du système entier, dans /etc/environment.
L'étape la plus importante pour les services
Si votre application tourne comme service systemd, le lien symbolique des alternatives ne fait que la moitié du travail. Un service démarre avec son propre environnement, et si un ancien chemin absolu figure dans ExecStart, aucun update-alternatives au monde n'y changera quoi que ce soit. Indiquez le chemin complet pour que la version soit fixée indépendamment de l'état du système :
[Service]
Environment="JAVA_HOME=/usr/lib/jvm/temurin-21-jdk-amd64"
ExecStart=/usr/lib/jvm/temurin-21-jdk-amd64/bin/java -Xms4G -Xmx4G -jar server.jar nogui
Ensuite, il faut impérativement recharger la configuration, sinon l'ancienne définition reste active :
systemctl daemon-reload
systemctl restart minecraft
Nos articles créer un service systemd et démarrer automatiquement un serveur Minecraft montrent à quoi ressemble une telle unit dans son intégralité. Le même piège vaut pour les scripts de démarrage lancés via screen ou tmux, ainsi que pour les panels comme Pterodactyl, qui fixent la version de Java dans l'image du conteneur (container) et non sur le système hôte.
Le cas inverse : Java est trop récent
Nettement plus rare, mais plus déroutant, voici l'autre cas de figure. Vous lancez un ancien modpack ou un vieil outil de build sur un serveur fraîchement installé avec Java 21 et vous voyez apparaître la courte phrase Unsupported class file major version 65, alors que tout est pourtant à jour. Ici, une bibliothèque signale qu'elle ne sait pas quoi faire du format de bytecode de votre nouvel environnement d'exécution. Les déclencheurs typiques sont les modpacks Forge pour 1.12.2, les anciennes versions de Gradle et les chargeurs de plugins qui ont pris de l'âge.
La solution n'est pas de supprimer le Java récent. Installez plutôt l'ancienne version en parallèle et appelez-la de façon ciblée avec son chemin absolu. Le mécanisme des alternatives est fait exactement pour cela, et c'est précisément pour cette raison qu'il vaut la peine de garder Java 8 et Java 21 en même temps sur un système. Sur Ubuntu, cela se fait directement depuis les dépôts standard, sur Debian via Temurin :
apt install -y temurin-8-jdk
/usr/lib/jvm/temurin-8-jdk-amd64/bin/java -version
Dans le script de démarrage du service concerné, remplacez ensuite java par ce chemin complet. Le Java par défaut du système reste intact, toutes les autres applications continuent de fonctionner comme avant.
Si le démarrage échoue malgré le changement
L'erreur de version a disparu, mais le serveur ne démarre toujours pas. C'est normal et cela a presque toujours l'une de ces trois causes.
D'anciens flags de démarrage. Quand on passe de Java 8 à 17 ou 21, on traîne souvent des paramètres de démarrage qui n'existent plus. Le grand classique est l'ancien garbage collector, supprimé dans Java 14 :
Unrecognized VM option 'UseConcMarkSweepGC'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Retirez -XX:+UseConcMarkSweepGC et toutes les options CMS associées de la commande de démarrage. Les versions modernes de Java utilisent G1 par défaut, et pour les serveurs Minecraft, les flags Aikar actuels constituent une meilleure base. Le message nomme toujours l'option gênante, vous n'avez donc pas à deviner.
Pas assez de RAM. Si Could not reserve enough space for object heap apparaît après le changement, la valeur derrière -Xmx dépasse la mémoire libre. Les versions récentes de Java respectent les limites de conteneur et de cgroup plus strictement que Java 8. Vérifiez la mémoire disponible et lisez au besoin notre article sur le swap et les erreurs Out of Memory.
Plus aucun Java dans le système des alternatives. Quand on désinstalle l'ancienne version avec trop de zèle, on obtient update-alternatives: error: no alternatives for java ou simplement command not found. Cela se répare en une minute en réinstallant n'importe quel paquet JRE, rien n'est perdu au passage. La prudence s'impose seulement avec apt autoremove lorsque d'autres paquets s'appuient sur default-jre : vérifiez la liste des paquets à supprimer avant de confirmer.
Comment savoir que cela a fonctionné
Ne vous fiez pas à la simple absence du message d'erreur, vérifiez plutôt trois points l'un après l'autre.
Premièrement, la version dans votre shell :
java -version 2>&1 | head -n 1
Deuxièmement, la version avec laquelle le processus tourne réellement. Le coup d'œil à /proc montré plus haut est ici l'outil le plus honnête, car il ne fait confiance ni aux variables d'environnement ni aux liens symboliques. Si ls -l /proc/PID/exe pointe vers le répertoire JVM souhaité, le changement est vraiment arrivé à destination.
Troisièmement, le log de l'application. Sur un serveur Minecraft, la ligne Done (12.345s)! For help, type "help" prouve que le démarrage est allé jusqu'au bout. Sur un service systemd, vous vérifiez cela avec :
systemctl status minecraft
journalctl -u minecraft -n 50 --no-pager
Si vous voulez en avoir le cœur net, il est aussi possible de demander à la JVM d'afficher sa propre configuration. C'est pratique quand plusieurs installations de Java sont en jeu et que vous devez en identifier une sans ambiguïté :
java -XshowSettings:properties -version
Dans la sortie, vous trouverez entre autres java.home et java.version. La question de savoir quelle installation travaille en ce moment est ainsi définitivement tranchée.
En résumé
Le nombre dans l'erreur n'est pas un numéro d'erreur, mais une indication de version : la majeure moins 44 donne la version de Java, 52 correspond à Java 8, 55 à Java 11, 61 à Java 17 et 65 à Java 21. Le message long avec has been compiled by a more recent version signifie que votre Java est trop ancien, tandis que le texte court Unsupported class file major version sans autre contexte indique le plus souvent un Java trop récent. Installez la version qui convient, gardez à l'esprit que Debian 12 ne propose que Java 17 et Debian 13 uniquement Java 21 et 25 dans les dépôts standard, puis activez vraiment cette version, au besoin avec un chemin absolu dans l'unit systemd. Pour contrôler, un coup d'œil à /proc/PID/exe suffit : vous saurez alors avec certitude, et non approximativement, quel Java exécute votre application.
Si vous installez un serveur de zéro et voulez éviter ces pièges dès le départ, nos articles sur la configuration d'un nouveau serveur root et sur l'installation d'un serveur Minecraft sur Debian vous aideront à démarrer proprement.
Questions fréquentes
Que signifie exactement « class file version 65.0 » ?
De quelle version de Java ai-je besoin pour mon serveur Minecraft ?
J'ai installé Java 21, mais java -version affiche toujours Java 17. Pourquoi ?
Pourquoi openjdk-21-jre-headless n'existe-t-il pas sur Debian 12 ?
L'erreur se limite à « Unsupported class file major version 65 », sans autre texte. Que faire ?
Comment savoir quel Java utilise un processus déjà en cours ?
Après le passage à Java 21, le serveur démarre avec « Unrecognized VM option ». Que s'est-il passé ?
2026 KernelHost GmbH. Tous droits réservés. Ce guide est protégé par le droit d'auteur. Sa republication sur d'autres sites web, même partielle ou sous une forme modifiée, n'est pas autorisée sans notre accord écrit. Les citations accompagnées de la source et d'un lien sont expressément les bienvenues.

