Java-Fehler "Unsupported class file major version" beheben
Die Zahl im Fehler verrät alles: 52 ist Java 8, 55 ist Java 11, 61 ist Java 17, 65 ist Java 21. So finden Sie heraus, welches Java wirklich läuft, und schalten die richtige Version scharf.
Sie starten einen Minecraft-Server, ein Plugin oder ein Build-Werkzeug, und statt des erwarteten Startvorgangs steht im Terminal eine Zahl, die auf den ersten Blick nichts sagt: class file version 65.0. Die gute Nachricht ist, dass diese Zahl die Diagnose bereits vollständig enthält. Sie müssen sie nur lesen können. Dieser Beitrag zeigt, wie Sie aus der Zahl die benötigte Java-Version ableiten, wie Sie herausfinden, welches Java auf Ihrem Server tatsächlich läuft (das ist häufig nicht das, was Sie denken), und wie Sie die richtige Version dauerhaft aktiv schalten.
Zwei verschiedene Fehlermeldungen, zwei verschiedene Ursachen
Der Wortlaut ist entscheidend, weil sich hinter den beiden gängigen Meldungen genau entgegengesetzte Probleme verbergen. Die erste stammt von der Java Virtual Machine selbst:
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
Diese Meldung bedeutet immer dasselbe: Die Anwendung wurde mit einem neueren Java gebaut, als Sie installiert haben. Die erste Zahl ist das, was die Anwendung mitbringt, die zweite Zahl ist das, was Ihre Laufzeitumgebung versteht. Im Beispiel oben verlangt die Software Java 21, installiert ist Java 17.
Die zweite Variante sieht ähnlich aus, kommt aber aus einer anderen Ecke:
java.lang.IllegalArgumentException: Unsupported class file major version 65
Diese kurze Form wirft nicht die JVM, sondern eine Bibliothek, die Bytecode einliest und analysiert, in aller Regel ASM. Sie taucht bei Gradle, bei alten Plugin-Ladern und bei älteren Server-Kernen auf. Hier ist die Lage meist umgekehrt: Ihr Java ist zu neu für die Software, die den Bytecode lesen will. Wer diese beiden Meldungen verwechselt, installiert die falsche Richtung und wundert sich, dass der Fehler bleibt. Merken Sie sich als Faustregel: Steht der lange Satz mit has been compiled by a more recent version da, brauchen Sie ein neueres Java. Steht nur der kurze Satz da, brauchen Sie vermutlich ein älteres.
Die Zahl entschlüsseln: Major-Version minus 44
Die Umrechnung ist einfacher, als die meisten Anleitungen es darstellen. Die Class-File-Major-Version minus 44 ergibt die Java-Version. 65 minus 44 ist 21, fertig. Die Regel gilt lückenlos ab Java 1.1 und wird sich auch in Zukunft nicht ändern, weil jede neue Java-Hauptversion die Zahl um genau eins erhöht.
| Class file version | Java-Version | Typischer Fundort |
|---|---|---|
| 52 | Java 8 | Minecraft bis 1.16.5, alte Forge-Modpacks, ältere Enterprise-Software |
| 53 | Java 9 | selten, Übergangsversion |
| 55 | Java 11 | viele Bibliotheken, ältere Spring-Anwendungen |
| 60 | Java 16 | Minecraft 1.17.x |
| 61 | Java 17 | Minecraft 1.18 bis 1.20.4, sehr viele aktuelle Plugins |
| 65 | Java 21 | Minecraft ab 1.20.5, also alle 1.21er, moderne Server-Kerne |
| 69 | Java 25 | brandneue Builds, aktuelles LTS-Release |
Die Zwischenwerte funktionieren nach derselben Regel: 62 ist Java 18, 63 ist Java 19, 64 ist Java 20, 66 ist Java 22 und so weiter. Die .0 hinter der Zahl ist die Minor-Version und spielt praktisch nie eine Rolle.
Was das für Minecraft konkret heißt
Die Zuordnung für Minecraft-Server ist eindeutig und lässt sich auswendig lernen. Bis einschließlich 1.16.5 gilt Java 8, für 1.17.x mindestens Java 16, von 1.18 bis 1.20.4 mindestens Java 17, ab 1.20.5 (und damit für die gesamte 1.21er-Reihe) Java 21. Wenn also im Log class file version 65.0 auftaucht und Sie gerade auf eine aktuelle Version aktualisiert haben, ist die Ursache gefunden, bevor Sie überhaupt in die Konfiguration schauen.
Welches Java läuft wirklich?
Der häufigste Denkfehler bei dieser Fehlerklasse ist die Annahme, dass die Ausgabe von java -version in Ihrer SSH-Sitzung auch für den laufenden Dienst gilt. Das stimmt oft nicht. Fangen Sie trotzdem hier an:
java -version
Die Ausgabe nennt in der ersten Zeile die Version, etwa openjdk version "21.0.11" 2026-04-15. Wenn stattdessen bash: java: command not found erscheint, ist überhaupt kein Java im Suchpfad, und die Anwendung wird von einem Startskript mit absolutem Pfad gestartet. Sehen Sie nach, welche Laufzeitumgebungen installiert sind:
ls /usr/lib/jvm
readlink -f "$(command -v java)"
update-alternatives --display java
readlink -f löst die Symlink-Kette auf und zeigt Ihnen die tatsächlich ausgeführte Binärdatei, zum Beispiel /usr/lib/jvm/java-17-openjdk-amd64/bin/java. Das ist wichtiger als die Versionsnummer allein, weil Sie diesen Pfad später brauchen.
Die mittlere Zeile ist bewusst mit command -v geschrieben und nicht mit dem verbreiteteren which. which ist ein eigenes Programm, und in der Minimalinstallation von AlmaLinux 9 und 10, Rocky Linux 9 und Oracle Linux 9 ist es nicht enthalten. Dort scheitert die which-Variante zweifach: erst which: command not found, dann readlink: missing operand. command -v steckt in der Shell selbst und läuft überall.
Für einen bereits laufenden Prozess gibt es einen Weg, der keinen Zweifel offen lässt. Er beantwortet die Frage, mit welchem Java der Dienst wirklich gestartet wurde, unabhängig von Suchpfad und Umgebungsvariablen:
ls -l /proc/$(pgrep -f server.jar | head -n 1)/exe
Der Symlink exe zeigt auf die ausführbare Datei des Prozesses. Steht dort ein anderer Pfad als erwartet, haben Sie die Ursache: Der Dienst startet mit einem anderen Java als Ihre Shell. Das passiert regelmäßig bei systemd-Units, weil diese eine eigene, minimale Umgebung mitbringen und Ihr JAVA_HOME aus der .bashrc dort schlicht nicht existiert.
Die Class-Version direkt aus der JAR-Datei lesen
Manchmal wollen Sie wissen, welches Java eine Datei verlangt, bevor Sie sie überhaupt starten. Das geht ohne Installation zusätzlicher Werkzeuge. Jede .class-Datei beginnt mit der Signatur CAFEBABE, danach folgen zwei Byte Minor- und zwei Byte Major-Version. Das achte Byte ist also die gesuchte Zahl:
unzip -p server.jar net/minecraft/bundler/Main.class | od -An -tu1 -N8
Die Ausgabe lautet dann etwa 202 254 186 190 0 0 0 65. Die ersten vier Zahlen sind die Signatur, die letzte ist Ihre Antwort: 65, also Java 21. Bei anderen Programmen ersetzen Sie den Klassenpfad entsprechend, den passenden Namen liefert unzip -l server.jar oder der Eintrag Main-Class in META-INF/MANIFEST.MF. Wenn ein JDK installiert ist, geht es auch bequemer:
javap -verbose -cp server.jar net.minecraft.bundler.Main | grep major
Bei Plugins ist dieser Trick besonders nützlich. Wenn ein einzelnes Plugin den Serverstart abbricht, prüfen Sie dessen Hauptklasse und wissen sofort, ob das Plugin zu neu für Ihren Server-Kern ist oder umgekehrt.
Die passende Java-Version installieren
Hier trennen sich die Distributionen deutlich, und pauschale Anleitungen scheitern genau an dieser Stelle. Der Stand aus echten Systemen, geprüft im Juli 2026:
| Paket | Debian 13 | Debian 12 | Ubuntu 24.04 | Ubuntu 22.04 |
|---|---|---|---|---|
| openjdk-8-jre-headless | fehlt | fehlt | 8u492 | 8u492 |
| openjdk-11-jre-headless | fehlt | fehlt | 11.0.31 | 11.0.31 |
| openjdk-17-jre-headless | fehlt | 17.0.19 | 17.0.19 | 17.0.19 |
| openjdk-21-jre-headless | 21.0.11 | fehlt | 21.0.11 | 21.0.11 |
| openjdk-25-jre-headless | 25.0.3 | fehlt | 25.0.3 | 25.0.3 |
Lesen Sie diese Tabelle einmal in Ruhe, sie erspart Ihnen viel Zeit. Debian 12 kennt ausschließlich Java 17, Debian 13 kennt Java 17 nicht mehr, sondern nur 21 und 25. Wer also auf Debian 12 einen 1.21er-Minecraft-Server betreiben will oder auf Debian 13 ein Programm mit class file version 61.0, findet in den Standardquellen nichts Passendes. Ubuntu ist an dieser Stelle großzügiger und liefert von Java 8 bis 25 alles aus einer Hand.
Prüfen Sie vor dem Installieren, ob das Paket überhaupt verfügbar ist:
apt update
apt-cache policy openjdk-21-jre-headless
Steht bei Kandidat beziehungsweise Candidate ein (keine), gibt es das Paket in Ihrer Version nicht. Andernfalls installieren Sie es. Für das reine Ausführen genügt die JRE, das -headless-Paket spart die grafischen Abhängigkeiten und ist auf einem Server immer die richtige Wahl:
apt install -y openjdk-21-jre-headless
Wer selbst kompiliert oder Gradle beziehungsweise Maven einsetzt, braucht das JDK statt der JRE, also openjdk-21-jdk-headless. Ausführlichere Wege beschreiben unsere Beiträge zu Java 17 auf Debian und Java 21 auf Debian.
Wenn die Distribution die Version nicht anbietet: Adoptium Temurin
Für alle Fälle, die die Standardquellen nicht abdecken, gibt es die Paketquelle von Adoptium. Sie liefert Temurin 8 bis 26 für Debian 12, Debian 13, Ubuntu 22.04 und Ubuntu 24.04 und ist damit die einzige Lösung, die auf jedem dieser Systeme jede benötigte Version bereitstellt. Wichtig: Der früher übliche Weg über apt-key ist abgekündigt, der Schlüssel gehört heute nach /etc/apt/keyrings/ und wird per signed-by genau dieser einen Quelle zugeordnet.
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
Der awk-Aufruf setzt automatisch den richtigen Codenamen ein, also trixie, bookworm, noble oder jammy. Wenn apt update danach mit Conflicting values set for option Signed-By abbricht, existiert bereits eine ältere Adoptium-Quelle, meist über extrepo angelegt. Suchen Sie sie in /etc/apt/sources.list.d/ und entfernen Sie die doppelte Datei.
AlmaLinux, Rocky Linux und RHEL
Auf der Red-Hat-Familie heißen die Pakete anders und tragen die Version im Namen ohne openjdk-Präfix am Anfang:
dnf install -y java-21-openjdk-headless
AlmaLinux 9, Rocky Linux 9 und Oracle Linux 9 führen die volle Reihe von java-1.8.0-openjdk-headless bis java-25-openjdk-headless. AlmaLinux 10 hat dagegen denselben Schnitt gemacht wie Debian 13 und kennt nur noch 21 und 25, ein dnf install java-17-openjdk-headless endet dort mit No match for argument.
Auch das Werkzeug zum Umschalten heißt hier schlicht alternatives, und update-alternatives ist nur ein Symlink darauf. Es verhält sich aber nicht gleich: alternatives --list nimmt kein Argument. Das von Debian gewohnte update-alternatives --list java gibt dort nur den Hilfetext aus und endet mit Rückgabewert 2. Verwenden Sie alternatives --list | grep java oder alternatives --display java, letzteres meldet dann java - status is auto. statt der Debian-Form java - auto mode.
Die Installationspfade tragen auf der Red-Hat-Familie die vollständige Paketversion im Verzeichnisnamen, also etwa /usr/lib/jvm/java-21-openjdk-21.0.11.0.10-1.el9.x86_64, und nicht die kurze Debian-Form mit Architektur-Suffix. Nur AlmaLinux 10 legt zusätzlich den kurzen Symlink java-21-openjdk an. Schreiben Sie den Pfad also nicht ab, sondern holen Sie ihn aus alternatives --display java.
Ein Verhalten, das hier besonders gemein ist: Nach der Installation von Java 17 neben einem bereits vorhandenen Java 21 stellte alternatives auf AlmaLinux 9 den Link /usr/bin/java selbsttätig auf die ältere Version 17 um. Wer also die zweite Version nur nachinstalliert, um sie gezielt für eine Altanwendung zu nutzen, ändert dabei unbeabsichtigt das Standard-Java des ganzen Systems. Setzen Sie nach jeder Zusatzinstallation ausdrücklich alternatives --set java <Pfad> und prüfen Sie mit java -version nach.
Die richtige Version aktiv schalten
Installiert heißt nicht aktiv. Nach der Installation eines zweiten JDK zeigt java -version oft weiterhin die alte Version, weil der Symlink /usr/bin/java unverändert bleibt. Auf Debian und Ubuntu regelt das der Alternatives-Mechanismus:
update-alternatives --list java
update-alternatives --config java
Der zweite Befehl zeigt eine nummerierte Liste und fragt nach Ihrer Auswahl. Danach steht die Auswahl auf manual und wird von künftigen Paketinstallationen nicht mehr überschrieben, was genau so gewollt ist. Wer das ohne Rückfrage skripten will, nutzt die Set-Variante mit dem vollen Pfad:
update-alternatives --set java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java
Setzen Sie zusätzlich JAVA_HOME, wenn Build-Werkzeuge im Spiel sind. Gradle und Maven ignorieren den Symlink und richten sich nach dieser Variablen:
export JAVA_HOME=/usr/lib/jvm/temurin-21-jdk-amd64
$JAVA_HOME/bin/java -version
Beachten Sie, dass ein export nur in der laufenden Sitzung gilt. Für Dienste hilft es überhaupt nicht: Nach dem nächsten Neustart nimmt der Dienst wieder die alte Java-Version, weil er die Variable nie gesehen hat. Dauerhaft gehört JAVA_HOME deshalb in die systemd-Unit als Environment= oder, systemweit, nach /etc/environment.
Der wichtigste Schritt bei Diensten
Läuft Ihre Anwendung als systemd-Dienst, ist der Alternatives-Symlink nur die halbe Miete. Ein Dienst startet mit eigener Umgebung, und wenn dort ein alter absoluter Pfad in ExecStart steht, ändert kein update-alternatives der Welt etwas daran. Tragen Sie den vollen Pfad ein, damit die Version unabhängig vom Systemzustand feststeht:
[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
Danach unbedingt neu einlesen, sonst läuft weiter die alte Definition:
systemctl daemon-reload
systemctl restart minecraft
Wie eine solche Unit vollständig aussieht, zeigen unsere Beiträge systemd-Service erstellen und Minecraft-Server automatisch starten. Dieselbe Falle gilt für Startskripte, die per screen oder tmux laufen, sowie für Panels wie Pterodactyl, die die Java-Version im Container-Image festlegen und nicht auf dem Hostsystem.
Der umgekehrte Fall: Java ist zu neu
Deutlich seltener, dafür verwirrender, ist der andere Fall. Sie starten ein älteres Modpack oder ein altes Build-Werkzeug auf einem frisch aufgesetzten Server mit Java 21 und bekommen den kurzen Satz Unsupported class file major version 65 zu sehen, obwohl doch alles aktuell ist. Hier meldet eine Bibliothek, dass sie mit dem Bytecode-Format Ihrer neuen Laufzeitumgebung nichts anfangen kann. Typische Auslöser sind Forge-Modpacks für 1.12.2, ältere Gradle-Versionen und in die Jahre gekommene Plugin-Lader.
Die Lösung ist nicht, das neue Java zu entfernen. Installieren Sie stattdessen die alte Version parallel und sprechen Sie sie gezielt mit absolutem Pfad an. Genau dafür ist der Alternatives-Mechanismus gebaut, und genau deshalb lohnt es sich, Java 8 und Java 21 gleichzeitig auf einem System zu halten. Auf Ubuntu geht das direkt aus den Standardquellen, auf Debian über Temurin:
apt install -y temurin-8-jdk
/usr/lib/jvm/temurin-8-jdk-amd64/bin/java -version
Im Startskript des betroffenen Dienstes ersetzen Sie dann java durch diesen vollen Pfad. Das systemweite Standard-Java bleibt unangetastet, alle anderen Anwendungen laufen weiter wie bisher.
Wenn es nach dem Wechsel trotzdem nicht startet
Der Versionsfehler ist weg, aber der Server startet immer noch nicht. Das ist normal und hat fast immer eine von drei Ursachen.
Alte Startflags. Wer von Java 8 auf 17 oder 21 wechselt, schleppt oft Startparameter mit, die es nicht mehr gibt. Der Klassiker ist der alte Garbage Collector, der in Java 14 entfernt wurde:
Unrecognized VM option 'UseConcMarkSweepGC'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Entfernen Sie -XX:+UseConcMarkSweepGC und alle zugehörigen CMS-Optionen aus dem Startbefehl. Moderne Java-Versionen nutzen G1 standardmäßig, und für Minecraft-Server sind die aktuellen Aikar-Flags die bessere Grundlage. Die Meldung nennt die störende Option immer beim Namen, Sie müssen also nicht raten.
Zu wenig Arbeitsspeicher. Wenn nach dem Wechsel Could not reserve enough space for object heap erscheint, ist der Wert hinter -Xmx größer als der freie Speicher. Neuere Java-Versionen beachten Container- und Cgroup-Grenzen strenger als Java 8. Prüfen Sie den freien Speicher und lesen Sie gegebenenfalls unseren Beitrag zu Swap und Out-of-Memory.
Kein Java mehr im Alternatives-System. Wer die alte Version übereifrig deinstalliert, bekommt update-alternatives: error: no alternatives for java oder schlicht command not found. Das lässt sich durch Neuinstallation eines beliebigen JRE-Pakets in einer Minute reparieren, es geht dabei nichts verloren. Vorsicht ist nur bei apt autoremove geboten, wenn andere Pakete auf default-jre aufbauen: Prüfen Sie die Liste der zu entfernenden Pakete, bevor Sie bestätigen.
Woran Sie erkennen, dass es funktioniert hat
Verlassen Sie sich nicht auf die Abwesenheit der Fehlermeldung, sondern prüfen Sie drei Punkte nacheinander.
Erstens die Version in Ihrer Shell:
java -version 2>&1 | head -n 1
Zweitens die Version, mit der der Prozess wirklich läuft. Der oben gezeigte Blick auf /proc ist hier das ehrlichste Werkzeug, weil er weder Umgebungsvariablen noch Symlinks vertraut. Zeigt ls -l /proc/PID/exe auf das gewünschte JVM-Verzeichnis, ist der Wechsel wirklich angekommen.
Drittens das Log der Anwendung. Bei einem Minecraft-Server ist die Zeile Done (12.345s)! For help, type "help" der Beleg dafür, dass der Start vollständig durchgelaufen ist. Bei einem systemd-Dienst prüfen Sie das mit:
systemctl status minecraft
journalctl -u minecraft -n 50 --no-pager
Wenn Sie es ganz genau wissen wollen, lässt sich die JVM auch dazu bringen, ihre eigene Konfiguration auszugeben. Das ist praktisch, wenn mehrere Java-Installationen im Spiel sind und Sie eine davon eindeutig identifizieren müssen:
java -XshowSettings:properties -version
In der Ausgabe finden Sie unter anderem java.home und java.version. Damit ist die Frage, welche Installation gerade arbeitet, endgültig geklärt.
Kurz zusammengefasst
Die Zahl im Fehler ist keine Fehlernummer, sondern eine Versionsangabe: Major minus 44 ergibt die Java-Version, 52 ist Java 8, 55 ist Java 11, 61 ist Java 17, 65 ist Java 21. Der lange Meldungstext mit has been compiled by a more recent version bedeutet, dass Ihr Java zu alt ist, der kurze Text Unsupported class file major version ohne weiteren Kontext deutet meist auf ein zu neues Java hin. Installieren Sie die passende Version, achten Sie darauf, dass Debian 12 nur Java 17 und Debian 13 nur Java 21 und 25 in den Standardquellen führt, und schalten Sie die Version anschließend wirklich aktiv, im Zweifel mit absolutem Pfad in der systemd-Unit. Zur Kontrolle genügt ein Blick auf /proc/PID/exe, dann wissen Sie sicher statt ungefähr, welches Java Ihre Anwendung ausführt.
Wenn Sie einen Server neu aufsetzen und diese Fallstricke von vornherein vermeiden wollen, helfen unsere Beiträge zur Einrichtung eines neuen Rootservers und zur Installation eines Minecraft-Servers auf Debian beim sauberen Start.
Häufige Fragen
Was bedeutet "class file version 65.0" genau?
Welche Java-Version brauche ich für meinen Minecraft-Server?
Ich habe Java 21 installiert, aber java -version zeigt weiter Java 17. Warum?
Warum gibt es auf Debian 12 kein openjdk-21-jre-headless?
Der Fehler lautet nur "Unsupported class file major version 65" ohne weiteren Text. Was tun?
Wie finde ich heraus, welches Java ein bereits laufender Prozess benutzt?
Nach dem Umstieg auf Java 21 startet der Server mit "Unrecognized VM option". Was ist passiert?
2026 KernelHost GmbH. Alle Rechte vorbehalten. Diese Anleitung ist urheberrechtlich geschützt. Eine Veröffentlichung auf anderen Webseiten, auch auszugsweise oder in bearbeiteter Form, ist ohne unsere schriftliche Zustimmung nicht gestattet. Zitate mit Quellenangabe und Link sind ausdrücklich willkommen.

