Minecraft Server Crash Triage: The First 15 Minutes

Minecraft Server Crash Triage: The First 15 Minutes

Your phone buzzes at 3:04 a.m. and the Discord webhook says the server is down with 40 players online. What you do in the next fifteen minutes decides whether players lose a night or lose a world. This runbook exists to help you spend those minutes on the right commands instead of on panic and a blind restart.

It is written for owners and admins who can read a log but were never taught an order of operations. The timings come from our own crash lab: Paper 26.2, 16 vCPU, a 512 MB heap, an empty test world, and a systemd unit using Restart=on-failure with RestartSec=2. We ended the JVM three different ways and timed what systemd did about it. An empty world boots faster than your live one, so treat every number here as a floor, not a guarantee.

Why Most Crashes Are Not Crashes

A crash is a process that exits. systemd only restarts a process that exits. That single sentence explains almost every “it did not come back” page you will ever get, and it is the reason a triage runbook beats a monitoring dashboard at 3 a.m.

In the lab, a hard kill (kill -9) behaved exactly as advertised. systemd restarted the process in 2.07 seconds, and the server logged “Done” again 7.12 seconds after the kill. That is the happy path, and it is why people trust restart policies.

Out-of-memory was not the happy path. A purpose-built leak plugin drove the JVM to OutOfMemoryError 8.74 seconds after startup, and the server never auto-restarted within 120 seconds. The JVM stayed alive, thrashing in garbage collection, so systemd saw a running process rather than an exit. A frozen JVM was worse still: after a SIGSTOP, nothing restarted it within 95 seconds, and no watchdog thread-dump lines appeared, because a frozen JVM cannot run its own watchdog. External health checks are the only thing that catches that state.

The lesson: uptime is not health. Before you touch anything, work out which of those states you are actually in.

The First 15 Minutes, Minute by Minute

0-2 minutes: declare, stop the loop, preserve evidence

Declare the incident out loud in staff chat so two people are not debugging the same box. Then stop the restart loop with systemctl stop minecraft if the unit is cycling. A looping service rewrites latest.log on every boot and will erase the evidence you are about to collect.

systemctl status minecraft --no-pager
journalctl -u minecraft -n 200 --no-pager
tail -n 100 logs/latest.log
ps -o pid,rss,etime,cmd -C java

Copy, do not move, the whole logs folder and crash-reports to a dated directory outside the server root. If a Java process is still alive, take a heap dump before you kill it: jcmd <pid> GC.heap_info for a fast summary, then jcmd <pid> GC.heap_dump /var/backups/heap.hprof. The dump is large, so confirm free space first with df -h.

Classify the Failure

Exit codes tell you who ended the process. 137 means 128 + 9, SIGKILL: either you or the kernel OOM killer ended it without warning. 143 means 128 + 15, SIGTERM: a polite stop, usually systemctl stop or a shutdown command. Both count as failures to systemd unless you configured otherwise, which is why a clean planned restart can look identical to a crash in the journal.

Failure classSymptomAuto-recovered?First action
Clean shutdownExit 143, “Stopping server” in logNo, by designConfirm it was planned, then start
Hard exitExit 137 or 1, no shutdown linesYes, ~2 s in our testRead journal, check for OOM kill
OOM inside JVMOutOfMemoryError, process still aliveNoHeap dump, then restart by hand
Frozen JVMPort open, no ticks, no log linesNoThread dump, then hard restart
World corruptionFails during chunk load, repeatsLoops foreverStop unit, restore last good world
Plugin crash loopSame stack trace every bootLoops foreverStop unit, disable the plugin jar
Disk fullOdd IO errors, missing Done lineNodf -h and df -i

That is why a crash loop needs systemctl stop before you edit anything. While the unit keeps restarting, your edits race the boot sequence, half-written configs get read, and the log you need is truncated. Stop the service, fix the file, then start once and read the result. If you are unsure how much history you are losing, our guide to reading Minecraft server logs covers where Paper writes each message.

Stabilise and Recover

5-10 minutes: remove the cause, not the symptom

With the unit stopped, disable the suspect plugin by renaming the jar (mv plugins/Suspect.jar plugins/Suspect.jar.disabled) so a later restart cannot load it. Then confirm the JVM was not killed by the kernel rather than Java itself:

dmesg -T | grep -i oom
df -h / /var
df -i /
ss -lntp | grep 25565

Raising heap is the most misapplied fix on the internet. Set -Xms equal to -Xmx, leave room for the OS, the page cache, and any other JVM on the box, and remember that a heap larger than physical RAM converts a Java error into a kernel kill. A 512 MB heap was enough for an empty world and is nowhere near enough for 40 players with plugins, which is exactly why the lab numbers are floors.

If the world itself is the problem, restore the last known-good world and config set from your automated backups and accept the rollback. A partially loaded region file will otherwise crash you again on the next boot, ten seconds after players rejoin.

10-15 minutes: verify, then communicate

Join with a test account. Check TPS and MSPT with /tps and /mspt, watch chunk loads as you fly, confirm permissions and economy commands still resolve, and only then reopen the whitelist or the proxy. Tell players what happened in one sentence, when it was fixed, and whether anything rolled back. Silence is what turns a 12-minute outage into a trust problem.

Prevent the Next 3 A.M. Page

Automation covers exits, not health. Configure systemd.service with Restart=on-failure, a short RestartSec, and StartLimitBurst so a broken jar cannot hammer the CPU forever. Then add an external check that queries the port and TPS from outside the JVM, because in our SIGSTOP test the frozen process produced no watchdog output at all. For tuning advice, read the PaperMC documentation rather than copying flags from a forum post.

Alert on MSPT and player count, not just on process state. Pair that with scheduled restarts at a quiet hour, and write a postmortem every time.

  • Timeline: first alert, actions, recovery, in UTC.
  • Impact: minutes down, players affected, rollback depth.
  • Root cause: the specific plugin, file, or allocation.
  • Detection gap: why monitoring missed it or paged late.
  • Corrective actions: each with an owner and a date.

Automated vs. manual recovery

  • Automated pros: fast, consistent, works while you sleep; 2.07 s beats any human response.
  • Automated cons: restarts on exit only, hides root causes, and can loop a corrupt world.
  • Manual pros: preserves evidence, catches OOM and frozen states, fixes the cause.
  • Manual cons: slow, depends on who is awake, easy to skip steps under pressure.

Use both. Let systemd handle exits, and let a human handle anything a restart fails to fix twice.

Common mistakes and how to avoid them

  • Restarting first. You overwrite the log that names the cause. Copy evidence at minute zero.
  • Editing configs during a crash loop. Stop the unit; racing boots produce half-read files.
  • Raising heap blindly. Bigger than RAM means the kernel kills you, not Java.
  • Trusting uptime. A frozen JVM reports “active (running)” while doing nothing.
  • Never testing restores. A backup you have not restored is a guess.
  • Ignoring inodes. df -i catches a full disk that df -h hides.

Expert tip: keep a one-page card taped to your desk with the five commands above. Under pressure, nobody remembers flags, and a card beats a search engine.

Frequently Asked Questions

What does exit code 137 mean for a Minecraft server?

The process was ended by SIGKILL, which is 128 + 9. Either someone ran kill -9 or the Linux OOM killer stepped in. Check dmesg -T | grep -i oom and the unit’s journal before restarting.

Why did systemd not restart my server after an OutOfMemoryError?

Because the JVM never exited. It stayed alive and thrashed while systemd kept seeing a running process. In our lab test it did not recover within 120 seconds. You must restart it by hand, and take a heap dump first if you want to find the leak.

How do I stop a Minecraft server crash loop?

Run systemctl stop minecraft so the unit cannot restart, then read journalctl -u minecraft -n 200 and logs/latest.log. Rename the suspect plugin jar or roll back the world, then start the service once and watch the full boot.

How long should a Minecraft server take to restart after a crash?

On our test box systemd relaunched the JVM 2.07 seconds after a hard kill, and the server logged Done again 7.12 seconds later. A production world with plugins and pregenerated chunks takes far longer, so plan for 30 to 90 seconds and alert on anything beyond that.

Conclusion

Fifteen minutes of ordered work beats three hours of guessing. Stop the loop, keep the evidence, classify the failure, remove the cause, then verify before you reopen. If a crash ever looks like a freeze, remember that no JVM can diagnose itself once it has stopped scheduling, which is why your monitoring has to live outside it. For official flag reference, keep the jcmd documentation and the kernel OOM tunables bookmarked. Then rehearse the runbook on a test box this week, while nobody is watching.

Generative AI was used to research and add structure to the original content so I can inform you as best as possible. All content has been reviewed by me.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Search

Minecraft Server Tips and Tricks