Jak czytać crash report serwera Minecraft: krok po kroku (2026)

Jak czytać crash report serwera Minecraft: krok po kroku (2026)

Serwer właśnie padł, w konsoli czerwona ściana tekstu, a w crash-reports/ świeży plik na 800 linii. Jeśli zdarza się to raz w tygodniu i za każdym razem zgadujesz, który plugin jest winny, ten poradnik jest dla ciebie. Rozkładamy na czynniki strukturę crash reportu, czytamy stack trace oczami admina Paper 1.21, odróżniamy Java-side crash od natywnego JVM crash i wskazujemy winny plugin w sekundach.

Napisane pod Paper i Folia 1.21+ na Java 21, ale 90% dotyczy też Spigot, Purpur, Fabric i Forge. Wszystkie nazwy klas i exceptionów są prawdziwe, nic nie wymyślone.

Gdzie serwer zostawia crash report

Gdy Minecraft łapie fatal exception w głównym wątku tick, vanilla sam dumpuje raport. Trzy lokalizacje są ważne i wszystkie trzy trzeba sprawdzić:

  • crash-reports/crash-YYYY-MM-DD_HH.MM.SS-server.txt obok server.jar. To główny artefakt, generowany przez net.minecraft.CrashReport zaraz przed śmiercią procesu.
  • hs_err_pid<PID>.log w katalogu roboczym serwera. Plik pochodzi od samej JVM HotSpot, pisany przez natywny kod runtime, gdy crash NIE jest w twoim kodzie Java tylko w samej VM: SIGSEGV, brak natywnej pamięci, bug JIT.
  • logs/latest.log i zrolowane logs/*.log.gz. Stack trace zwykle dubluje się tutaj plus kontekst minuty przed awarią. Bez latest.log crash report jest często bezużyteczny, bo nie widać, co plugin robił sekundę przed padem.

Paper czasem dorzuca czwarty plik: debug/ z dumpem TPS i wątków, jeśli watchdog zdążył wystartować. Na Paper 1.21.4+ sprawdź też ten katalog.

Najpierw: skopiuj plik w całości. Nie edytuj go, nie wycinaj "szumu". Pełny crash report to dokładnie to, czego potrzebuje autor pluginu, a w szumie często ukrywa się przyczyna.

Anatomia crash-XXXX.txt

Plik wygląda strasznie, ale układ ma mechaniczny. Typowy crash:

---- Minecraft Crash Report ----
// Don't be sad, have a hug! <3

Time: 2026-04-15 18:42:11
Description: Exception ticking world

java.lang.NullPointerException: Cannot invoke "org.bukkit.entity.Player.getInventory()" because the return value of "org.bukkit.Bukkit.getPlayer(String)" is null
    at com.example.shopgui.ShopGuiPlus.onPlayerJoin(ShopGuiPlus.java:142) ~[ShopGUIPlus-1.94.0.jar:?]
    at sun.reflect.GeneratedMethodAccessor412.invoke(Unknown Source) ~[?:?]
    at org.bukkit.plugin.EventExecutor.execute(EventExecutor.java:123) ~[paper-api-1.21.4.jar:?]
    at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.callEvent(PaperPluginManagerImpl.java:177) ~[paper-1.21.4.jar:?]
    at net.minecraft.server.players.PlayerList.placeNewPlayer(PlayerList.java:215) ~[paper-1.21.4.jar:?]
    ...

Warstwa po warstwie. Linia-marker ---- Minecraft Crash Report ---- istnieje, by narzędzia jak mcprofile rozpoznawały to jako crash report, a nie zwykły log. Potem śmieszny cytat, humor Mojanga z net.minecraft.CrashReport.getErrorComment od 2012.

Time i Description dają kontekst. Description to to, co main thread robił w momencie exceptiona. Najczęstsze wartości: Exception ticking world, Exception in server tick loop, Loading entities, Unexpected error, Watching Server. Jeśli opis brzmi Watching Server, dump powstał z watchdoga po freezu, a nie z samego exceptiona, i stack trace pokazuje NIE winnego, ale wątek, który zawisł.

Dalej idzie sama klasa exceptiona i stos wywołań. To kluczowa część i poświęcamy jej kolejną sekcję.

Czytanie stack trace: gdzie padło vs kto winny

Kolejność w stack trace: na górze najnowszy frame (gdzie poszedł throw), na dole najstarszy (zwykle Thread.run). Początkujący admini często obwiniają najwyższą linię i się mylą.

Reguła jest prosta. Idź z góry na dół i znajdź pierwszy frame, który NIE jest vanilla Minecraft, NIE jest Bukkit/Paper API i NIE jest standardową biblioteką Java. Pakiety:

  • net.minecraft.*, com.mojang.* to vanilla. Rzadko winowajca.
  • org.bukkit.*, io.papermc.*, org.spigotmc.* to API serwera. Też rzadko winne.
  • java.*, jdk.*, sun.* to JDK. Crash tutaj to OOM, problem JIT albo wciśnięte null do API.
  • Wszystko inne to kod trzeci. To twój winowajca.

W przykładzie pierwsza obca linia to at com.example.shopgui.ShopGuiPlus.onPlayerJoin(ShopGuiPlus.java:142) ~[ShopGUIPlus-1.94.0.jar:?]. Pakiet com.example.shopgui, jar ShopGUIPlus-1.94.0.jar, winowajca w sekundę. Plik ShopGuiPlus.java linia 142.

Ogon w nawiasach kwadratowych ~[ShopGUIPlus-1.94.0.jar:?] Paper dodaje specjalnie dla wygody. Na Spigocie tego nie ma, trzeba ręcznie znajdować pakiet. com.example.shopgui w Google prowadzi do ShopGUIPlus w pięć sekund.

Jeśli stack trace NIE zawiera obcego kodu i wszystko leży w net.minecraft.*, to albo bug vanilli (rzadko), uszkodzenie świata lub skutki cudzego buga: plugin zniszczył entity wcześniej, vanilla crashuje minutę później przy sprzątaniu. W takim razie otwórz latest.log i szukaj WARN/ERROR w minucie przed crashem.

Najczęstsze exceptions: znaczenie i naprawa

Dziewięć na dziesięć crashy to jeden z sześciu exceptionów. Znajomość wzorca oszczędza godzinę debuga.

NullPointerException. Ktoś wywołał metodę na obiekcie null. Java 14+ pisze diagnostykę Cannot invoke "X.method()" because Y is null. Mówi DOKŁADNIE, co było null. Zwykle plugin nie sprawdził Bukkit.getPlayer() lub world.getBlockAt().getState() na null. Fix: zaktualizować plugin lub zgłosić autorowi z trace.

ConcurrentModificationException. Wątek A modyfikuje kolekcję, gdy wątek B po niej iteruje. Plaga pluginów dotykających świata z async-taska. Operacje na świecie, chunkach, entities lub inwentarzach MUSZĄ być na main thread przez Bukkit.getScheduler().runTask(plugin, ...). Jeśli winny pakiet zawiera Async, Tasks lub Sync, to prawie na pewno on.

OutOfMemoryError: Java heap space. Heap się skończył. To nie bug kodu, to memory leak albo za mały -Xmx. Przed OOM JVM prawie zawsze pisze hs_err_pid lub java_pid<PID>.hprof (jeśli włączone -XX:+HeapDumpOnOutOfMemoryError). Otwórz hprof w Eclipse MAT lub VisualVM i zobacz, która klasa trzyma najwięcej. Na 1.21 typowi winowajcy: Citizens (zawieszone NPC), wielkie rendery Dynmap, pluginy z cachującym HashMap<UUID, ...> bez cleanupu.

StackOverflowError. Nieskończona rekurencja. Najczęściej cykliczne PlaceholderAPI: placeholder A rozwija B, B rozwija A. Albo EventListener wystrzeliwuje event ponownie wchodzący w tego samego listenera. Stack trace pokazuje TE SAME linie setki razy, szukaj wzorca.

NoClassDefFoundError / ClassNotFoundException. Plugin odwołuje się do klasy spoza classpath. Najczęściej:

  1. Plugin zależy od ProtocolLib/Vault/PlaceholderAPI, a nie wrzuciłeś go do plugins/.
  2. Zaktualizowałeś Paper, plugin używa klasy Mojang-mapped, której już nie ma (np. net.minecraft.server.v1_17_R1.* po 1.17 zniknął).
  3. Konflikt wersji: dwa pluginy zaszyły różne wersje tej samej biblioteki, ClassLoader wziął nie tę.

IllegalStateException na Paper 1.21 zwykle oznacza "dotknąłeś świata poza main thread", "iterator nieważny" lub "plugin disabled". Komunikat jest zwykle wprost.

Tabela: exception, prawdopodobna przyczyna, pierwszy krok

ExceptionPrawdopodobna przyczynaPierwszy krok
NullPointerExceptionPlugin nie sprawdził null po API callZnaleźć pierwszy obcy pakiet w trace, zaktualizować
ConcurrentModificationExceptionAsync-kod modyfikuje świat/entityWyłączyć plugin z "Async" w nazwie i przetestować
OutOfMemoryError: Java heap spaceMemory leak lub -Xmx zbyt małySprawdzić -Xmx, otworzyć heap dump w MAT
StackOverflowErrorCykliczna rekurencja (często PAPI)Szukać powtarzających się linii w trace
NoClassDefFoundErrorBrak zależności lub konflikt wersjiSprawdzić obecność wymaganych pluginów
IllegalStateExceptionAsync dostęp do API lub disabled pluginPrzeczytać komunikat, zwykle wprost

hs_err_pid: gdy crashuje sama JVM

Jeśli w katalogu serwera pojawi się hs_err_pid12345.log, to inna kategoria crasha. Java exceptions JVM łapie czysto. Gdy widzisz hs_err_pid, sama maszyna wirtualna padła: SIGSEGV, SIGBUS, brak natywnej pamięci, bug JIT.

Plik zaczyna się tak:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f4a8c1d3a40, pid=12345, tid=12378
#
# JRE version: OpenJDK Runtime Environment Temurin-21.0.4+7 (21.0.4+7) (build 21.0.4+7-LTS)
# Java VM: OpenJDK 64-Bit Server VM Temurin-21.0.4+7 (21.0.4+7-LTS, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# C  [libc.so.6+0x9aa40]
#

Na co patrzeć:

  • Problematic frame to najważniejsza linia. Jeśli jest C [libc.so.6+...] lub C [libfreetype.so+...], to natywna biblioteka OS. Zwykle sterownik NIC, glibc na starym Ubuntu, OpenSSL.
  • Jeśli Problematic frame to J net.minecraft.server.MinecraftServer.tick, to bug JIT, podnieś Javę do najnowszego patcha.
  • JRE version ma znaczenie. Java 17.0.2 miała znanego buga JIT, 21.0.0 GA też miała. Przejdź na najnowszego Temurina LTS, patrz adoptium.net.
  • Sekcja THREAD pokazuje, co robił wątek. Jeśli to "Server thread" lecący przez org.bukkit.craftbukkit.v1_21_R3.*, serwer po prostu tickował i padł w natywie.
  • Sekcja Memory ważna przy OOM. Patrz Native Memory Tracking jeśli JVM startowała z -XX:NativeMemoryTracking=summary.

Jeśli hs_err_pid pojawia się regularnie, sprawdź RAM przez memtest86 przez noc (na dedyku). Wadliwa kość daje SIGSEGV w losowych miejscach. Częściej niż chciałbyś.

Latest.log: kontekst minuty przed crashem

Crash report pokazuje sam moment awarii. Co działo się WCZEŚNIEJ siedzi w logs/latest.log. Otwórz i znajdź timestamp 30-60 sekund przed Time z crash reportu. Interesują cię:

  • [WARN] i [ERROR] od pluginów. Często plugin pięć minut pisze ostrzeżenia, potem pada.
  • Can't keep up! i komunikaty watchdoga. Serwer freezeował przed śmiercią.
  • Loginy graczy. Jeśli crash zawsze przy login konkretnego UUID, zwykle ich playerdata/<uuid>.dat jest popsute.
  • Komendy admina lub pluginów. Operacje WorldEdit, /reload (nigdy nie rób /reload na live), masowe kicki.

Użyteczna kombo: latest.log dwie sekundy przed crashem pisze [WARN] [ShopGUIPlus] Failed to load shop config for player Steve, a stack crash reportu kończy się w ShopGuiPlus.onPlayerJoin. Winowajca potwierdzony bez zgadywania.

Szukanie winnego pluginu: od pakietu do downloadu

Trace pokazał at com.example.shopgui.ShopGuiPlus.onPlayerJoin. Co dalej:

  1. Otwórz plugins/ i znajdź jar po nazwie z nawiasów ShopGUIPlus-1.94.0.jar. Zapamiętaj wersję.
  2. Bez nawiasów (Spigot): unzip -p plugins/*.jar plugin.yml | grep -A1 main: i dopasuj main: do pakietu. Output mówi, który jar zawiera pakiet.
  3. Google na com.example.shopgui zwykle prowadzi do SpigotMC resources, Modrinth lub GitHuba autora.
  4. Sprawdź wersję pluginu vs ostatnie wydanie. Każdy zasób SpigotMC ma changelog i issue tracker.
  5. Jeśli ostatnia wersja jest nowsza i changelog ma "fix NullPointerException on player join", podnoś. Załatwione.
  6. Jeśli już jesteś na ostatniej, otwórz issue. Załącz CAŁY crash report (przez pastebin, mclo.gs albo gist GitHub), wersję Paper (/version), wersję Java (java -version) i kroki reprodukcji.

Dla pluginów Paperowych dobry zwyczaj: sprawdzić, czy taki crash nie jest już zgłoszony w Paper issues. Czasem winny jest sam Paper, zwłaszcza zaraz po nowym release.

Narzędzia, które przyspieszają triage

mclo.gs bierze crash report i wyróżnia pakiety pluginów osobnymi blokami. Wygodne do dzielenia w Discordowych kanałach supportu.

mcprofile.io parsuje crashe i koloruje stack frames wg właściciela. Brak płatnych funkcji, wszystko za darmo.

Dla dumpów hprof Eclipse MAT jest standardem od piętnastu lat. Otwiera dumpy do 8 GB na laptopie, patrz eclipse.dev/mat.

IntelliJ IDEA Community otwiera hs_err_pid i dzieli go na zakładki. Też za darmo.

Jeśli nie chcesz nic instalować lokalnie, zwykły grep pokrywa 80% przypadków: grep -A 30 "Stacktrace:" crash-reports/crash-*.txt daje sam stack bez szumu.

Jak zgłosić bug autorowi pluginu

Dobry issue to różnica między "zamknięty w dzień" i "ignorowany pół roku". Minimum:

  • Wersja pluginu (/version <Plugin>).
  • Wersja serwera (/version, cała linia z numerem buildu Paper).
  • Wersja Java (java -version).
  • Pełny crash report przez mclo.gs lub gist GitHub. Nigdy nie wklejaj 800 linii w treść issue.
  • latest.log z pięciu minut przed crashem, też przez mclo.gs.
  • Kroki reprodukcji. Jeśli crash losowy, napisz: "happens randomly 1-2 times per day, no obvious trigger".
  • Lista pluginów lecących obok winowajcy.

Czego NIE robić: nie wklejać surowego tekstu, nie edytować crash reportu ("usunąłem szum"), nie pisać tylko "crashed pls fix".

FAQ

Co ważniejsze, crash-report.txt czy hs_err_pid?

Jeśli masz oba, zacznij od crash-report.txt. To Java exception z sensownym stack trace i identyfikowalnym pluginem. hs_err_pid czytasz, gdy crash-report.txt w ogóle nie powstał lub zawiera tylko opis Watching Server bez użytecznego trace.

Dlaczego trace pokazuje tylko net.minecraft.* i żadnego pluginu?

Dwa powody. Albo crash padł na wątku, który nie odpalał kodu pluginu (chunk gen, sieć), a plugin zepsuł dane wcześniej. Albo to dump watchdoga, więc stack pokazuje zamrożony main thread, nie przyczynę freezu. W obu przypadkach otwórz latest.log i szukaj WARN 30 sekund przed czasem crasha.

Serwer crashuje na starcie i nie powstaje crash report. Gdzie patrzeć?

Jeśli proces ginie przed utworzeniem crash-reports/, log idzie na stdout. Odpal serwer w screen/tmux lub z 2>&1 | tee start.log i sprawdź stdout. Zwykle to NoClassDefFoundError od pluginu z brakującą zależnością albo niekompatybilną Javą.

Jak odróżnić OOM od zwykłego laga?

OOM widać jako java.lang.OutOfMemoryError: Java heap space albo GC Overhead Limit Exceeded. Jeśli tego nie ma, ale TPS spadł do zera i watchdog ubił serwer minutę później, to NIE OOM tylko długi GC pause albo zawieszony plugin. Odpal Spark profiler (/spark profiler) i nagraj flame graph.

Co robić z serwerem padającym za każdym razem na innym crash report?

Klasyczny objaw problemu sprzętowego lub uszkodzonego świata. Najpierw memtest86 przez noc na dedyku. Potem sprawdź świat przez chunky albo regionfixer. Na zarządzanym hostingu poproś o przeniesienie na inny węzeł, czasem hałaśliwy sąsiad OOMuje twoją JVM.

Czy wyłączyć -XX:+HeapDumpOnOutOfMemoryError?

Nie, zostaw włączone. Dump powstaje raz przy OOM i jest mniej więcej rozmiaru -Xmx. Przy -Xmx16G to 16 GB, miej wolne miejsce na dysku. Bez heap dumpa znalezienie memory leaka jest możliwe, ale dużo dłuższe.

Jeśli twój serwer pada raz w tygodniu, a każdy crash report rymuje się z poprzednim, prawdopodobnie już wiesz, który plugin jest winny. Ale jeśli pady są losowe i nie ma czytelnego wzorca, sprawdź, czy nie wali w ciebie burza pakietów obciążająca stos sieciowy i zatykająca prawdziwym graczom logowanie. MineGuard zatrzymuje takie ataki zanim dojdą do Minecraft i zostawia w logach tylko prawdziwe crashe pluginów.


Chroń swój serwer przed atakami DDoS

Darmowa ochrona z konfiguracją w 5 minut. 1 TB ruchu w zestawie.

Wypróbuj za darmo


Powiązane artykuły