Resolver o erro Java "Unsupported class file major version"
O número no erro diz tudo: 52 é Java 8, 55 é Java 11, 61 é Java 17 e 65 é Java 21. Veja como descobrir que Java corre realmente e como ativar a versão certa.
Arranca um servidor Minecraft, um plugin ou uma ferramenta de build e, em vez do arranque esperado, o terminal mostra um número que à primeira vista não diz nada: class file version 65.0. A boa notícia é que esse número já contém todo o diagnóstico. Só precisa de o saber ler. Este artigo mostra como deduzir a versão de Java necessária a partir do número, como descobrir que Java corre realmente no seu servidor (muitas vezes não é aquele que pensa) e como ativar a versão certa de forma permanente.
Duas mensagens de erro diferentes, duas causas diferentes
A formulação exata é decisiva, porque por trás das duas mensagens habituais escondem-se problemas exatamente opostos. A primeira vem da própria Java Virtual Machine:
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
Esta mensagem significa sempre o mesmo: a aplicação foi compilada com um Java mais recente do que aquele que tem instalado. O primeiro número é o que a aplicação traz consigo, o segundo é o que o seu ambiente de execução compreende. No exemplo acima, o software exige o Java 21 e o que está instalado é o Java 17.
A segunda variante parece semelhante, mas vem de outro lado:
java.lang.IllegalArgumentException: Unsupported class file major version 65
Esta forma curta não é lançada pela JVM, mas por uma biblioteca que lê e analisa bytecode, quase sempre o ASM. Aparece no Gradle, em carregadores de plugins antigos e em núcleos de servidor mais antigos. Aqui a situação costuma ser inversa: o seu Java é demasiado recente para o software que quer ler o bytecode. Quem confunde estas duas mensagens instala na direção errada e depois estranha que o erro se mantenha. Guarde esta regra prática: se aparecer a frase longa com has been compiled by a more recent version, precisa de um Java mais recente. Se aparecer apenas a frase curta, provavelmente precisa de um mais antigo.
Descodificar o número: versão major menos 44
A conversão é mais simples do que a maioria dos guias faz parecer. A versão major do ficheiro class menos 44 dá a versão do Java. 65 menos 44 é 21, e está feito. A regra vale sem falhas desde o Java 1.1 e também não vai mudar no futuro, porque cada nova versão principal do Java aumenta o número em exatamente uma unidade.
| Class file version | Versão do Java | Onde aparece normalmente |
|---|---|---|
| 52 | Java 8 | Minecraft até 1.16.5, modpacks Forge antigos, software empresarial mais antigo |
| 53 | Java 9 | rara, versão de transição |
| 55 | Java 11 | muitas bibliotecas, aplicações Spring mais antigas |
| 60 | Java 16 | Minecraft 1.17.x |
| 61 | Java 17 | Minecraft 1.18 até 1.20.4, muitos plugins atuais |
| 65 | Java 21 | Minecraft a partir de 1.20.5, ou seja, toda a série 1.21, núcleos de servidor modernos |
| 69 | Java 25 | builds acabadas de sair, versão LTS atual |
Os valores intermédios seguem a mesma regra: 62 é Java 18, 63 é Java 19, 64 é Java 20, 66 é Java 22 e assim por diante. O .0 a seguir ao número é a versão minor e, na prática, nunca tem importância.
O que isto significa em concreto para o Minecraft
A correspondência para servidores Minecraft é clara e vale a pena decorá-la. Até à 1.16.5, inclusive, aplica-se o Java 8; para a 1.17.x, no mínimo o Java 16; da 1.18 até à 1.20.4, no mínimo o Java 17; a partir da 1.20.5 (e portanto para toda a série 1.21), o Java 21. Ou seja, se no log surgir class file version 65.0 e tiver acabado de atualizar para uma versão recente, a causa está encontrada antes sequer de olhar para a configuração.
Que Java corre realmente?
O erro de raciocínio mais frequente nesta classe de problemas é assumir que o resultado de java -version na sua sessão SSH também vale para o serviço em execução. Muitas vezes não vale. Ainda assim, comece por aqui:
java -version
A primeira linha do resultado indica a versão, por exemplo openjdk version "21.0.11" 2026-04-15. Se em vez disso aparecer bash: java: command not found, não existe qualquer Java no caminho de pesquisa e a aplicação é arrancada por um script com caminho absoluto. Verifique que ambientes de execução estão instalados:
ls /usr/lib/jvm
readlink -f "$(command -v java)"
update-alternatives --display java
O readlink -f resolve a cadeia de symlinks e mostra-lhe o binário que é realmente executado, por exemplo /usr/lib/jvm/java-17-openjdk-amd64/bin/java. Isso é mais importante do que o número da versão isolado, porque vai precisar desse caminho mais à frente.
A linha do meio está escrita de propósito com command -v e não com o mais divulgado which. O which é um programa próprio e, na instalação mínima do AlmaLinux 9 e 10, do Rocky Linux 9 e do Oracle Linux 9, não vem incluído. Aí a variante com which falha duas vezes: primeiro which: command not found, depois readlink: missing operand. O command -v está na própria shell e funciona em todo o lado.
Para um processo já em execução existe um caminho que não deixa margem para dúvidas. Responde à pergunta de com que Java o serviço foi mesmo arrancado, independentemente do caminho de pesquisa e das variáveis de ambiente:
ls -l /proc/$(pgrep -f server.jar | head -n 1)/exe
O symlink exe aponta para o ficheiro executável do processo. Se aí estiver um caminho diferente do esperado, encontrou a causa: o serviço arranca com um Java diferente do da sua shell. Isso acontece com regularidade em units do systemd, porque estas trazem um ambiente próprio e mínimo, e o seu JAVA_HOME definido no .bashrc ali simplesmente não existe.
Ler a versão class diretamente do ficheiro JAR
Por vezes quer saber que Java um ficheiro exige antes sequer de o arrancar. Isso consegue-se sem instalar ferramentas adicionais. Cada ficheiro .class começa com a assinatura CAFEBABE, seguida de dois bytes de versão minor e dois bytes de versão major. O oitavo byte é, portanto, o número que procura:
unzip -p server.jar net/minecraft/bundler/Main.class | od -An -tu1 -N8
O resultado é então algo como 202 254 186 190 0 0 0 65. Os primeiros quatro números são a assinatura e o último é a sua resposta: 65, ou seja, Java 21. Noutros programas substitui o caminho da classe em conformidade; o nome certo é dado por unzip -l server.jar ou pela entrada Main-Class em META-INF/MANIFEST.MF. Se tiver um JDK instalado, há uma forma mais cómoda:
javap -verbose -cp server.jar net.minecraft.bundler.Main | grep major
Nos plugins este truque é especialmente útil. Se um único plugin interromper o arranque do servidor, verifique a respetiva classe principal e fica logo a saber se o plugin é demasiado recente para o seu núcleo de servidor ou o contrário.
Instalar a versão de Java adequada
É aqui que as distribuições se separam claramente, e é exatamente neste ponto que os guias genéricos falham. A situação em sistemas reais, verificada em julho de 2026:
| Pacote | Debian 13 | Debian 12 | Ubuntu 24.04 | Ubuntu 22.04 |
|---|---|---|---|---|
| openjdk-8-jre-headless | não incluído | não incluído | 8u492 | 8u492 |
| openjdk-11-jre-headless | não incluído | não incluído | 11.0.31 | 11.0.31 |
| openjdk-17-jre-headless | não incluído | 17.0.19 | 17.0.19 | 17.0.19 |
| openjdk-21-jre-headless | 21.0.11 | não incluído | 21.0.11 | 21.0.11 |
| openjdk-25-jre-headless | 25.0.3 | não incluído | 25.0.3 | 25.0.3 |
Leia esta tabela uma vez com calma, poupa-lhe muito tempo. O Debian 12 conhece exclusivamente o Java 17; o Debian 13 já não conhece o Java 17, apenas o 21 e o 25. Quem quiser correr um servidor Minecraft 1.21 no Debian 12, ou no Debian 13 um programa com class file version 61.0, não encontra nada de adequado nas fontes padrão. O Ubuntu é mais generoso neste ponto e fornece tudo, do Java 8 ao 25, a partir da mesma fonte.
Antes de instalar, verifique se o pacote está sequer disponível:
apt update
apt-cache policy openjdk-21-jre-headless
Se em Candidato ou Candidate aparecer (nenhum), o pacote não existe na sua versão. Caso contrário, instale-o. Para apenas executar basta o JRE; o pacote -headless poupa as dependências gráficas e é sempre a escolha certa num servidor:
apt install -y openjdk-21-jre-headless
Quem compila código próprio ou usa o Gradle ou o Maven precisa do JDK em vez do JRE, ou seja, do openjdk-21-jdk-headless. Caminhos mais detalhados são descritos nos nossos artigos sobre Java 17 no Debian e Java 21 no Debian.
Quando a distribuição não oferece a versão: Adoptium Temurin
Para todos os casos que as fontes padrão não cobrem existe o repositório da Adoptium. Fornece o Temurin 8 a 26 para Debian 12, Debian 13, Ubuntu 22.04 e Ubuntu 24.04 e é, por isso, a única solução que disponibiliza em cada um destes sistemas todas as versões necessárias. Importante: o antigo caminho através do apt-key está descontinuado; hoje a chave pertence a /etc/apt/keyrings/ e é associada, através de signed-by, exatamente a esta única 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
A chamada ao awk insere automaticamente o nome de código correto, ou seja, trixie, bookworm, noble ou jammy. Se o apt update abortar depois disso com Conflicting values set for option Signed-By, já existe uma fonte Adoptium mais antiga, normalmente criada através do extrepo. Procure-a em /etc/apt/sources.list.d/ e remova o ficheiro duplicado.
AlmaLinux, Rocky Linux e RHEL
Na família Red Hat os pacotes têm outros nomes e trazem a versão no nome, sem o prefixo openjdk no início:
dnf install -y java-21-openjdk-headless
O AlmaLinux 9, o Rocky Linux 9 e o Oracle Linux 9 disponibilizam a série completa, de java-1.8.0-openjdk-headless até java-25-openjdk-headless. Já o AlmaLinux 10 fez o mesmo corte que o Debian 13 e conhece apenas o 21 e o 25: ali um dnf install java-17-openjdk-headless termina com No match for argument.
Também a ferramenta para trocar de versão se chama aqui simplesmente alternatives, e o update-alternatives é apenas um symlink para ela. Mas não se comporta da mesma maneira: o alternatives --list não aceita argumentos. O update-alternatives --list java, habitual no Debian, limita-se ali a mostrar o texto de ajuda e termina com o código de saída 2. Use alternatives --list | grep java ou alternatives --display java; este último indica então java - status is auto. em vez da forma do Debian java - auto mode.
Na família Red Hat os caminhos de instalação incluem a versão completa do pacote no nome do diretório, por exemplo /usr/lib/jvm/java-21-openjdk-21.0.11.0.10-1.el9.x86_64, e não a forma curta do Debian com sufixo de arquitetura. Só o AlmaLinux 10 cria adicionalmente o symlink curto java-21-openjdk. Não copie o caminho daqui, retire-o antes de alternatives --display java.
Um comportamento particularmente traiçoeiro: depois de instalar o Java 17 ao lado de um Java 21 já existente, o alternatives no AlmaLinux 9 mudou por iniciativa própria o link /usr/bin/java para a versão mais antiga, a 17. Ou seja, quem instala a segunda versão apenas para a usar de forma dirigida numa aplicação antiga acaba por alterar sem querer o Java padrão de todo o sistema. Depois de cada instalação adicional, defina explicitamente alternatives --set java <Caminho> e confirme com java -version.
Ativar a versão certa
Instalado não significa ativo. Depois de instalar um segundo JDK, o java -version mostra muitas vezes na mesma a versão antiga, porque o symlink /usr/bin/java permanece inalterado. No Debian e no Ubuntu isso é gerido pelo mecanismo alternatives:
update-alternatives --list java
update-alternatives --config java
O segundo comando mostra uma lista numerada e pergunta pela sua escolha. A partir daí a seleção fica em manual e deixa de ser sobreposta por futuras instalações de pacotes, que é precisamente o que se pretende. Quem quiser fazer isto num script, sem perguntas, usa a variante set com o caminho completo:
update-alternatives --set java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java
Defina adicionalmente o JAVA_HOME se houver ferramentas de build envolvidas. O Gradle e o Maven ignoram o symlink e orientam-se por esta variável:
export JAVA_HOME=/usr/lib/jvm/temurin-21-jdk-amd64
$JAVA_HOME/bin/java -version
Tenha em conta que um export só vale para a sessão em curso. Para serviços não ajuda de todo: no reinício seguinte, o serviço volta a usar a versão antiga do Java, porque nunca chegou a ver a variável. De forma permanente, o JAVA_HOME pertence por isso à unit do systemd, como Environment=, ou, para todo o sistema, ao /etc/environment.
O passo mais importante no caso dos serviços
Se a sua aplicação correr como serviço do systemd, o symlink do alternatives resolve apenas metade do problema. Um serviço arranca com um ambiente próprio e, se aí estiver um caminho absoluto antigo em ExecStart, nenhum update-alternatives do mundo muda isso. Indique o caminho completo, para que a versão fique fixada independentemente do estado do 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
A seguir é imprescindível recarregar, caso contrário continua a valer a definição antiga:
systemctl daemon-reload
systemctl restart minecraft
O aspeto completo de uma unit destas é mostrado nos nossos artigos criar um serviço systemd e iniciar um servidor Minecraft automaticamente. A mesma armadilha aplica-se a scripts de arranque que correm com screen ou tmux, bem como a painéis como o Pterodactyl, que definem a versão do Java na imagem do container e não no sistema host.
O caso inverso: o Java é demasiado recente
Bastante mais raro, mas também mais confuso, é o caso contrário. Arranca um modpack antigo ou uma ferramenta de build antiga num servidor acabado de instalar com Java 21 e recebe a frase curta Unsupported class file major version 65, apesar de estar tudo atualizado. Aqui é uma biblioteca a comunicar que não consegue lidar com o formato de bytecode do seu novo ambiente de execução. Os causadores típicos são modpacks Forge para a 1.12.2, versões antigas do Gradle e carregadores de plugins que já têm muitos anos.
A solução não passa por remover o Java novo. Instale antes a versão antiga em paralelo e invoque-a de forma dirigida com o caminho absoluto. É exatamente para isso que o mecanismo alternatives foi construído, e é exatamente por isso que compensa manter o Java 8 e o Java 21 ao mesmo tempo num sistema. No Ubuntu isso faz-se diretamente a partir das fontes padrão, no Debian através do Temurin:
apt install -y temurin-8-jdk
/usr/lib/jvm/temurin-8-jdk-amd64/bin/java -version
No script de arranque do serviço afetado substitui então o java por este caminho completo. O Java padrão de todo o sistema fica intacto e todas as outras aplicações continuam a funcionar como antes.
Se, mesmo depois da mudança, continuar a não arrancar
O erro de versão desapareceu, mas o servidor continua a não arrancar. Isso é normal e tem quase sempre uma de três causas.
Flags de arranque antigas. Quem passa do Java 8 para o 17 ou o 21 arrasta muitas vezes parâmetros de arranque que já não existem. O clássico é o antigo garbage collector, removido no Java 14:
Unrecognized VM option 'UseConcMarkSweepGC'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Remova o -XX:+UseConcMarkSweepGC e todas as opções CMS associadas do comando de arranque. As versões modernas do Java usam o G1 por predefinição e, para servidores Minecraft, as flags Aikar atuais são a melhor base. A mensagem indica sempre pelo nome a opção problemática, por isso não precisa de adivinhar.
Memória insuficiente. Se depois da mudança aparecer Could not reserve enough space for object heap, o valor a seguir a -Xmx é maior do que a memória livre. As versões mais recentes do Java respeitam os limites de container e de cgroup de forma mais rigorosa do que o Java 8. Verifique a memória livre e, se for caso disso, leia o nosso artigo sobre swap e out of memory.
Já não há Java no sistema alternatives. Quem desinstala a versão antiga com demasiado zelo recebe update-alternatives: error: no alternatives for java ou simplesmente command not found. Isso resolve-se num minuto com a reinstalação de um pacote JRE qualquer, sem que nada se perca. Cuidado apenas com o apt autoremove quando outros pacotes assentam no default-jre: verifique a lista dos pacotes a remover antes de confirmar.
Como reconhece que resultou
Não se fie na simples ausência da mensagem de erro; verifique antes três pontos, um a seguir ao outro.
Primeiro, a versão na sua shell:
java -version 2>&1 | head -n 1
Segundo, a versão com que o processo corre realmente. O olhar sobre o /proc mostrado acima é aqui a ferramenta mais honesta, porque não confia nem em variáveis de ambiente nem em symlinks. Se o ls -l /proc/PID/exe apontar para o diretório da JVM pretendida, a mudança chegou mesmo ao destino.
Terceiro, o log da aplicação. Num servidor Minecraft, a linha Done (12.345s)! For help, type "help" é a prova de que o arranque decorreu por completo. Num serviço do systemd verifica isso com:
systemctl status minecraft
journalctl -u minecraft -n 50 --no-pager
Se quiser saber com toda a exatidão, também pode levar a JVM a mostrar a sua própria configuração. Isso é prático quando há várias instalações de Java envolvidas e precisa de identificar uma delas sem ambiguidade:
java -XshowSettings:properties -version
No resultado encontra, entre outros, o java.home e o java.version. Com isso fica definitivamente esclarecida a questão de saber que instalação está a trabalhar.
Em resumo
O número no erro não é um código de erro, mas uma indicação de versão: major menos 44 dá a versão do Java, 52 é Java 8, 55 é Java 11, 61 é Java 17 e 65 é Java 21. O texto longo com has been compiled by a more recent version significa que o seu Java é demasiado antigo; o texto curto Unsupported class file major version, sem mais contexto, aponta normalmente para um Java demasiado recente. Instale a versão adequada, tenha presente que o Debian 12 traz apenas o Java 17 e o Debian 13 apenas o Java 21 e o 25 nas fontes padrão, e ative depois a versão a sério, na dúvida com caminho absoluto na unit do systemd. Para controlo basta um olhar ao /proc/PID/exe: assim fica a saber com certeza, e não por aproximação, que Java executa a sua aplicação.
Se vai instalar um servidor do zero e quer evitar estas armadilhas à partida, os nossos artigos sobre a configuração de um novo servidor root e a instalação de um servidor Minecraft no Debian ajudam a começar bem.
Perguntas frequentes
O que significa exatamente "class file version 65.0"?
De que versão do Java preciso para o meu servidor Minecraft?
Instalei o Java 21, mas o java -version continua a mostrar o Java 17. Porquê?
Porque não existe o openjdk-21-jre-headless no Debian 12?
O erro é apenas "Unsupported class file major version 65", sem mais texto. O que fazer?
Como descubro que Java está a ser usado por um processo já em execução?
Depois de passar para o Java 21, o servidor arranca com "Unrecognized VM option". O que aconteceu?
2026 KernelHost GmbH. Todos os direitos reservados. Este guia está protegido por direitos de autor. A sua republicação noutros sites, na íntegra, em parte ou de forma editada, não é permitida sem o nosso consentimento por escrito. Citações com indicação da fonte e ligação são expressamente bem-vindas.

