Risolvere l'errore Java "Unsupported class file major version"
Il numero nell'errore dice già tutto: 52 è Java 8, 55 è Java 11, 61 è Java 17, 65 è Java 21. Ecco come scoprire quale Java gira davvero sul tuo server e come attivare la versione giusta.
Avvii un server Minecraft, un plugin o un tool di build e, al posto dell'avvio che ti aspettavi, nel terminale compare un numero che a prima vista non dice nulla: class file version 65.0. La buona notizia è che quel numero contiene già l'intera diagnosi. Devi solo saperlo leggere. Questo articolo ti mostra come ricavare dal numero la versione di Java necessaria, come scoprire quale Java gira davvero sul tuo server (spesso non è quello che pensi) e come attivare in modo stabile la versione giusta.
Due messaggi di errore diversi, due cause diverse
Il testo esatto è decisivo, perché dietro i due messaggi più comuni si nascondono problemi esattamente opposti. Il primo arriva dalla Java Virtual Machine stessa:
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
Questo messaggio significa sempre la stessa cosa: l'applicazione è stata compilata con un Java più recente di quello che hai installato. Il primo numero è quello che porta con sé l'applicazione, il secondo è quello che il tuo runtime riesce a capire. Nell'esempio qui sopra il software richiede Java 21, mentre è installato Java 17.
La seconda variante sembra simile, ma arriva da tutt'altra parte:
java.lang.IllegalArgumentException: Unsupported class file major version 65
Questa forma breve non viene lanciata dalla JVM, ma da una libreria che legge e analizza il bytecode, di norma ASM. Compare con Gradle, con vecchi caricatori di plugin e con core di server datati. Qui la situazione è quasi sempre rovesciata: il tuo Java è troppo recente per il software che vuole leggere il bytecode. Chi confonde i due messaggi installa nella direzione sbagliata e poi si stupisce che l'errore resti. Tieni a mente questa regola pratica: se compare la frase lunga con has been compiled by a more recent version, ti serve un Java più recente. Se compare solo la frase breve, con ogni probabilità te ne serve uno più vecchio.
Decifrare il numero: major version meno 44
Il calcolo è più semplice di come lo presentano quasi tutte le guide. La major version del class file meno 44 dà la versione di Java. 65 meno 44 fa 21, punto. La regola vale senza eccezioni da Java 1.1 in poi e non cambierà nemmeno in futuro, perché ogni nuova versione principale di Java alza il numero esattamente di uno.
| Class file version | Versione Java | Dove la trovi di solito |
|---|---|---|
| 52 | Java 8 | Minecraft fino alla 1.16.5, vecchi modpack Forge, software enterprise datato |
| 53 | Java 9 | rara, versione di transizione |
| 55 | Java 11 | molte librerie, applicazioni Spring meno recenti |
| 60 | Java 16 | Minecraft 1.17.x |
| 61 | Java 17 | Minecraft dalla 1.18 alla 1.20.4, moltissimi plugin attuali |
| 65 | Java 21 | Minecraft dalla 1.20.5 in poi, quindi tutte le 1.21, core di server moderni |
| 69 | Java 25 | build nuovissime, release LTS attuale |
I valori intermedi seguono la stessa regola: 62 è Java 18, 63 è Java 19, 64 è Java 20, 66 è Java 22 e così via. Lo .0 dopo il numero è la minor version e in pratica non conta mai.
Che cosa significa in concreto per Minecraft
L'abbinamento per i server Minecraft è netto e si impara a memoria. Fino alla 1.16.5 compresa serve Java 8, per la 1.17.x almeno Java 16, dalla 1.18 alla 1.20.4 almeno Java 17, dalla 1.20.5 in poi (e quindi per tutta la serie 1.21) Java 21. Se nel log compare class file version 65.0 e hai appena aggiornato a una versione recente, la causa è trovata ancora prima di aprire la configurazione.
Quale Java gira davvero?
L'errore di ragionamento più frequente con questa classe di problemi è dare per scontato che l'output di java -version nella tua sessione SSH valga anche per il servizio in esecuzione. Spesso non è così. Parti comunque da qui:
java -version
La prima riga dell'output riporta la versione, per esempio openjdk version "21.0.11" 2026-04-15. Se invece compare bash: java: command not found, nel percorso di ricerca non c'è alcun Java e l'applicazione viene avviata da uno script con percorso assoluto. Verifica quali runtime sono installati:
ls /usr/lib/jvm
readlink -f "$(command -v java)"
update-alternatives --display java
readlink -f risolve la catena di symlink e ti mostra il binario realmente eseguito, per esempio /usr/lib/jvm/java-17-openjdk-amd64/bin/java. Questo conta più del semplice numero di versione, perché quel percorso ti servirà più avanti.
La riga centrale usa di proposito command -v e non il più diffuso which. which è un programma a sé e nell'installazione minima di AlmaLinux 9 e 10, Rocky Linux 9 e Oracle Linux 9 non è incluso. Lì la variante con which fallisce due volte: prima which: command not found, poi readlink: missing operand. command -v invece è integrato nella shell stessa e funziona ovunque.
Per un processo già in esecuzione c'è una strada che non lascia spazio a dubbi. Risponde alla domanda su quale Java abbia davvero avviato il servizio, indipendentemente dal percorso di ricerca e dalle variabili d'ambiente:
ls -l /proc/$(pgrep -f server.jar | head -n 1)/exe
Il symlink exe punta al file eseguibile del processo. Se lì trovi un percorso diverso da quello atteso, hai la causa: il servizio parte con un Java diverso da quello della tua shell. Succede spesso con le unit systemd, perché portano con sé un ambiente proprio e ridotto, e il tuo JAVA_HOME definito nel .bashrc lì semplicemente non esiste.
Leggere la class version direttamente dal file JAR
A volte vuoi sapere quale Java richiede un file prima ancora di avviarlo. Si può fare senza installare tool aggiuntivi. Ogni file .class inizia con la firma CAFEBABE, seguita da due byte di minor version e due byte di major version. L'ottavo byte è quindi il numero che cerchi:
unzip -p server.jar net/minecraft/bundler/Main.class | od -An -tu1 -N8
L'output è più o meno 202 254 186 190 0 0 0 65. I primi quattro numeri sono la firma, l'ultimo è la tua risposta: 65, quindi Java 21. Con altri programmi sostituisci il percorso della classe di conseguenza, e il nome giusto lo trovi con unzip -l server.jar oppure nella voce Main-Class di META-INF/MANIFEST.MF. Se hai un JDK installato, c'è anche una via più comoda:
javap -verbose -cp server.jar net.minecraft.bundler.Main | grep major
Con i plugin questo trucco è particolarmente utile. Se un singolo plugin blocca l'avvio del server, controlla la sua classe principale e saprai subito se il plugin è troppo recente per il tuo core di server oppure il contrario.
Installare la versione di Java adatta
Qui le distribuzioni si differenziano parecchio ed è esattamente il punto in cui le guide generiche falliscono. Ecco la situazione rilevata su sistemi reali, verificata a luglio 2026:
| Pacchetto | Debian 13 | Debian 12 | Ubuntu 24.04 | Ubuntu 22.04 |
|---|---|---|---|---|
| openjdk-8-jre-headless | non incluso | non incluso | 8u492 | 8u492 |
| openjdk-11-jre-headless | non incluso | non incluso | 11.0.31 | 11.0.31 |
| openjdk-17-jre-headless | non incluso | 17.0.19 | 17.0.19 | 17.0.19 |
| openjdk-21-jre-headless | 21.0.11 | non incluso | 21.0.11 | 21.0.11 |
| openjdk-25-jre-headless | 25.0.3 | non incluso | 25.0.3 | 25.0.3 |
Leggi questa tabella con calma, ti farà risparmiare molto tempo. Debian 12 conosce soltanto Java 17, mentre Debian 13 non ha più Java 17 ma solo la 21 e la 25. Quindi chi vuole far girare un server Minecraft 1.21 su Debian 12, oppure un programma con class file version 61.0 su Debian 13, nelle fonti standard non trova nulla di adatto. Su questo punto Ubuntu è più generoso e fornisce tutto da Java 8 fino alla 25.
Prima di installare, verifica che il pacchetto sia davvero disponibile:
apt update
apt-cache policy openjdk-21-jre-headless
Se accanto a Candidato (in inglese Candidate) compare (nessuno), nella tua versione il pacchetto non esiste. Altrimenti puoi installarlo. Per la sola esecuzione basta la JRE, e il pacchetto -headless risparmia le dipendenze grafiche, quindi su un server è sempre la scelta giusta:
apt install -y openjdk-21-jre-headless
Se compili in proprio oppure usi Gradle o Maven, ti serve il JDK al posto della JRE, quindi openjdk-21-jdk-headless. Percorsi più dettagliati li descrivono i nostri articoli su Java 17 su Debian e Java 21 su Debian.
Se la distribuzione non offre la versione: Adoptium Temurin
Per tutti i casi che le fonti standard non coprono c'è il repository di Adoptium. Fornisce Temurin dalla 8 alla 26 per Debian 12, Debian 13, Ubuntu 22.04 e Ubuntu 24.04 ed è quindi l'unica soluzione che su ognuno di questi sistemi mette a disposizione qualsiasi versione ti serva. Importante: la vecchia strada tramite apt-key è deprecata, oggi la chiave va in /etc/apt/keyrings/ e viene associata con signed-by esattamente a quella singola fonte.
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
La chiamata ad awk inserisce automaticamente il nome in codice corretto, quindi trixie, bookworm, noble oppure jammy. Se poi apt update si interrompe con Conflicting values set for option Signed-By, esiste già una vecchia fonte Adoptium, di solito creata tramite extrepo. Cercala in /etc/apt/sources.list.d/ ed elimina il file doppione.
AlmaLinux, Rocky Linux e RHEL
Nella famiglia Red Hat i pacchetti hanno nomi diversi e portano la versione nel nome, senza il prefisso openjdk all'inizio:
dnf install -y java-21-openjdk-headless
AlmaLinux 9, Rocky Linux 9 e Oracle Linux 9 offrono la serie completa, da java-1.8.0-openjdk-headless fino a java-25-openjdk-headless. AlmaLinux 10 ha invece fatto lo stesso taglio di Debian 13 e conosce solo la 21 e la 25, tanto che lì un dnf install java-17-openjdk-headless finisce con No match for argument.
Anche il tool per cambiare versione qui si chiama semplicemente alternatives, e update-alternatives ne è solo un symlink. Il comportamento però non è identico: alternatives --list non accetta argomenti. Il update-alternatives --list java a cui sei abituato su Debian lì stampa solo il testo di aiuto e termina con codice di uscita 2. Usa alternatives --list | grep java oppure alternatives --display java, e quest'ultimo riporta java - status is auto. invece della forma Debian java - auto mode.
Nella famiglia Red Hat i percorsi di installazione contengono la versione completa del pacchetto nel nome della directory, quindi per esempio /usr/lib/jvm/java-21-openjdk-21.0.11.0.10-1.el9.x86_64, e non la forma breve di Debian con il suffisso di architettura. Solo AlmaLinux 10 crea in più il symlink breve java-21-openjdk. Non ricopiare quindi il percorso a mano, ricavalo da alternatives --display java.
Un comportamento particolarmente insidioso: dopo l'installazione di Java 17 accanto a un Java 21 già presente, su AlmaLinux 9 alternatives ha spostato da solo il link /usr/bin/java sulla versione più vecchia, la 17. Chi installa la seconda versione solo per usarla in modo mirato con una vecchia applicazione, cambia così senza volerlo il Java predefinito dell'intero sistema. Dopo ogni installazione aggiuntiva imposta quindi esplicitamente alternatives --set java <PERCORSO> e controlla il risultato con java -version.
Attivare davvero la versione giusta
Installata non vuol dire attiva. Dopo l'installazione di un secondo JDK, java -version mostra spesso ancora la vecchia versione, perché il symlink /usr/bin/java resta invariato. Su Debian e Ubuntu se ne occupa il meccanismo alternatives:
update-alternatives --list java
update-alternatives --config java
Il secondo comando mostra un elenco numerato e ti chiede quale versione scegliere. Dopo la scelta l'impostazione passa su manual e non viene più sovrascritta dalle installazioni di pacchetti successive, che è esattamente ciò che serve. Se vuoi metterlo in uno script senza domande, usa la variante set con il percorso completo:
update-alternatives --set java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java
Imposta anche JAVA_HOME se entrano in gioco tool di build. Gradle e Maven ignorano il symlink e si regolano su questa variabile:
export JAVA_HOME=/usr/lib/jvm/temurin-21-jdk-amd64
$JAVA_HOME/bin/java -version
Tieni presente che un export vale solo nella sessione corrente. Per i servizi non serve proprio a nulla: al riavvio successivo il servizio riprende la vecchia versione di Java, perché quella variabile non l'ha mai vista. In modo permanente JAVA_HOME va quindi nella unit systemd come Environment= oppure, a livello di intero sistema, in /etc/environment.
Il passaggio più importante con i servizi
Se la tua applicazione gira come servizio systemd, il symlink di alternatives è solo metà del lavoro. Un servizio parte con un ambiente proprio e, se in ExecStart è rimasto un vecchio percorso assoluto, nessun update-alternatives al mondo cambierà qualcosa. Inserisci il percorso completo, così la versione resta fissa a prescindere dallo stato del sistema:
[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
Subito dopo ricarica assolutamente la configurazione, altrimenti resta attiva la vecchia definizione:
systemctl daemon-reload
systemctl restart minecraft
Come si presenta una unit completa lo mostrano i nostri articoli creare un servizio systemd e avviare automaticamente un server Minecraft. La stessa trappola vale per gli script di avvio che girano tramite screen o tmux, e per pannelli come Pterodactyl, che fissano la versione di Java nell'immagine del container e non sul sistema host.
Il caso opposto: Java troppo recente
Nettamente più raro, ma anche più disorientante, è il caso contrario. Avvii un modpack datato o un vecchio tool di build su un server appena installato con Java 21 e ti ritrovi davanti la frase breve Unsupported class file major version 65, anche se tutto è aggiornato. Qui una libreria segnala che non sa che farsene del formato bytecode del tuo nuovo runtime. Le cause tipiche sono i modpack Forge per la 1.12.2, versioni datate di Gradle e caricatori di plugin ormai avanti con gli anni.
La soluzione non è rimuovere il Java nuovo. Installa invece la vecchia versione in parallelo e richiamala in modo mirato con il percorso assoluto. Il meccanismo alternatives è pensato esattamente per questo, ed è proprio per questo che conviene tenere Java 8 e Java 21 contemporaneamente sullo stesso sistema. Su Ubuntu si fa direttamente dalle fonti standard, su Debian tramite Temurin:
apt install -y temurin-8-jdk
/usr/lib/jvm/temurin-8-jdk-amd64/bin/java -version
Nello script di avvio del servizio interessato sostituisci poi java con questo percorso completo. Il Java predefinito di sistema resta intatto e tutte le altre applicazioni continuano a funzionare come prima.
Se dopo il cambio continua a non partire
L'errore di versione è sparito, ma il server continua a non avviarsi. È normale e quasi sempre la causa è una di tre.
Vecchi flag di avvio. Chi passa da Java 8 alla 17 o alla 21 si porta spesso dietro parametri che non esistono più. Il classico è il vecchio garbage collector, rimosso in Java 14:
Unrecognized VM option 'UseConcMarkSweepGC'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Rimuovi -XX:+UseConcMarkSweepGC e tutte le opzioni CMS collegate dal comando di avvio. Le versioni moderne di Java usano G1 come impostazione predefinita e, per i server Minecraft, gli attuali flag di Aikar sono una base migliore. Il messaggio indica sempre per nome l'opzione che dà problemi, quindi non devi tirare a indovinare.
Troppo poca RAM. Se dopo il cambio compare Could not reserve enough space for object heap, il valore dopo -Xmx è più grande della memoria libera. Le versioni recenti di Java rispettano i limiti di container e cgroup in modo più rigido rispetto a Java 8. Controlla la memoria libera e, se necessario, leggi il nostro articolo su swap e out of memory.
Nessun Java nel sistema alternatives. Chi disinstalla la vecchia versione con troppo entusiasmo ottiene update-alternatives: error: no alternatives for java oppure semplicemente command not found. Si ripara in un minuto reinstallando un qualsiasi pacchetto JRE e non si perde nulla. L'unica accortezza riguarda apt autoremove quando altri pacchetti dipendono da default-jre: controlla l'elenco dei pacchetti da rimuovere prima di confermare.
Come capisci che ha funzionato
Non fidarti dell'assenza del messaggio di errore, controlla invece tre punti uno dopo l'altro.
Primo, la versione nella tua shell:
java -version 2>&1 | head -n 1
Secondo, la versione con cui il processo gira davvero. Lo sguardo su /proc mostrato sopra è lo strumento più onesto, perché non si fida né delle variabili d'ambiente né dei symlink. Se ls -l /proc/PID/exe punta alla directory JVM desiderata, il cambio è andato davvero a segno.
Terzo, il log dell'applicazione. Su un server Minecraft la riga Done (12.345s)! For help, type "help" è la prova che l'avvio è arrivato in fondo. Con un servizio systemd lo verifichi così:
systemctl status minecraft
journalctl -u minecraft -n 50 --no-pager
Se vuoi la certezza assoluta, puoi anche far stampare alla JVM la sua stessa configurazione. Torna comodo quando sul sistema convivono più installazioni di Java e devi identificarne una senza ambiguità:
java -XshowSettings:properties -version
Nell'output trovi tra le altre cose java.home e java.version. Così la domanda su quale installazione stia effettivamente lavorando è chiarita in via definitiva.
In sintesi
Il numero nell'errore non è un codice di errore, ma un'indicazione di versione: major meno 44 dà la versione di Java, 52 è Java 8, 55 è Java 11, 61 è Java 17, 65 è Java 21. Il messaggio lungo con has been compiled by a more recent version significa che il tuo Java è troppo vecchio, mentre il testo breve Unsupported class file major version senza altro contesto indica di solito un Java troppo recente. Installa la versione adatta, tieni presente che nelle fonti standard Debian 12 offre solo Java 17 e Debian 13 solo Java 21 e 25, e poi attiva davvero quella versione, nel dubbio con il percorso assoluto nella unit systemd. Per il controllo basta un'occhiata a /proc/PID/exe, così sai con certezza e non solo all'incirca quale Java esegue la tua applicazione.
Se stai configurando un server da zero e vuoi evitare queste trappole fin dall'inizio, i nostri articoli sulla configurazione di un nuovo server root e sull'installazione di un server Minecraft su Debian ti aiutano a partire in modo pulito.
Domande frequenti
Che cosa significa esattamente "class file version 65.0"?
Quale versione di Java serve per il mio server Minecraft?
Ho installato Java 21, ma java -version mostra ancora Java 17. Perché?
Perché su Debian 12 non esiste openjdk-21-jre-headless?
L'errore è solo "Unsupported class file major version 65" senza altro testo. Che faccio?
Come scopro quale Java usa un processo già in esecuzione?
Dopo il passaggio a Java 21 il server si ferma con "Unrecognized VM option". Che cosa è successo?
2026 KernelHost GmbH. Tutti i diritti riservati. Questa guida è protetta dal diritto d'autore. La ripubblicazione su altri siti web, anche parziale o in forma modificata, non è consentita senza il nostro consenso scritto. Le citazioni con indicazione della fonte e un link sono le benvenute.

