Metadata-Version: 2.4
Name: forge-server-doctor
Version: 1.0.0
Summary: Reads a modded Minecraft crash report and tells you which mod actually broke it. Forge and NeoForge, 1.16-1.21.
Author: Jakoby Tuckta
License: LicenseRef-Proprietary-Free-Edition
Project-URL: Homepage, https://github.com/jaakoby/forge-server-doctor
Project-URL: Documentation, https://jaakoby.github.io/fix/
Project-URL: Source, https://github.com/jaakoby/forge-server-doctor
Keywords: minecraft,forge,neoforge,crash-report,modded-minecraft,minecraft-server,crash-analysis,log-analysis,troubleshooting
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Games/Entertainment
Classifier: Topic :: System :: Monitoring
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Dynamic: license-file

# forge-server-doctor

**Why won't my modded Minecraft server start?**

A 400-line crash report, a wall of `at net.minecraft...` frames, and
no indication which of your 200 mods caused it. That is the problem
this solves.

```
$ forge-doctor logs/latest.log

ENVIRONMENT
------------------------------------------------------------
  Minecraft        1.21.1
  Loader           21.1.72
  Java             21.0.4
  Mods             214
  Reached 'Done'   no

  CULPRIT (first non-vanilla frame):
    techmod-1.21.1-4.2.0.jar
    in com.example.tech.TechMod.<init>
```

It names a culprit on **any** report that has a stack trace,
including crashes it does not recognise -- which is the common case,
and the part other tools give up on. The method is deliberately
simple: walk the trace, skip every frame belonging to Minecraft, the
loader or the JDK, and report the first one that is left, along with
the jar Forge says it came from.

Constructor frames (`TechMod.<init>`) and static initialisers
(`<clinit>`) count, because dying in your own constructor is one of
the most common startup crashes there is.

### What this free edition does

- Names the culprit mod and the jar it came from, on any trace
- Six startup failures matched with the fix for each: EULA not
  accepted, port already in use, wrong Java version, out of memory,
  locked or corrupt world, and duplicate mod jars
- Reads plain `.log`, `.log.gz` and `crash-reports/*.txt`
- When nothing matches, it says so plainly and tells you what to
  check by hand, instead of implying the log is clean
- Links each finding to a page on how to be sure it is that, and
  what it gets mistaken for

### Honest limits

- It reads the log, not the game. It cannot know a mod is merely
  incompatible if nothing in the log says so.
- The first non-vanilla frame is a strong heuristic, not proof. A
  mod that wraps another mod's code will sometimes take the blame
  for it.
- Some logs do not annotate frames with a jar name at all. There it
  reports the Java **package** instead and says it could not
  identify the jar, rather than guessing one.
- Deobfuscated names only. A fully obfuscated trace gives it nothing
  to read.

## Install

```bash
pip install forge-server-doctor
```

One module, Python 3.8+, **no dependencies** -- it imports nothing outside the standard library.

## More

The paid edition adds 18 more failure modes matched in the log with
the fix for each, plus `--json` for scripting. Culprit naming is
deliberately in the free edition -- withholding the only hard part
would be the wrong way round.

Exit codes are meaningful and non-zero on purpose: `0` nothing
fatal, `1` a fatal finding, `2` bad arguments. That lets you gate a
start script on it (`forge-doctor logs/latest.log || exit`). It also
fooled my own test harness twice, which is why it is written down
here.

Diagnostic pages for every finding: <https://jaakoby.github.io/fix/>
Source: <https://github.com/jaakoby/forge-server-doctor>
Full edition: <https://kaiven.gumroad.com/l/forge-server-doctor>

---

*Built by Jakoby Tuckta with Claude. Every claim above is something the tool does on a real log; see the repo's tests.*
