# Singleplayer Server Crash: fastutil ClassNotFoundException

## Status: Open (multiple users, Feb 24-27 2026)

## Symptom

Singleplayer server crashes immediately after DualAuth Agent installs successfully:

```
Exception in thread "main" java.lang.NoClassDefFoundError: it/unimi/dsi/fastutil/objects/ObjectArrayList
    at com.hypixel.hytale.plugin.early.EarlyPluginLoader.<clinit>(EarlyPluginLoader.java:34)
    at com.hypixel.hytale.Main.main(Main.java:36)
Caused by: java.lang.ClassNotFoundException: it.unimi.dsi.fastutil.objects.ObjectArrayList
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
```

Server exits with code 1. Multiplayer works fine for the same user.

## Affected Users

1. **ヅ𝚃 JAYED !** (Feb 24) — Windows x86_64, had AOT cache errors before fastutil crash
2. **Asentrix** (Feb 27) — Windows x86_64 (NT 10.0.26200.0), RTX 4060, Launcher v2.4.4, NO AOT cache errors

- Reproduces 100% on singleplayer, every attempt
- Multiplayer works fine for both users
- macOS/Linux users are NOT affected

## What Works

- Java wrapper correctly strips `-XX:+UseCompactObjectHeaders`
- Java wrapper correctly injects `--disable-sentry`
- DualAuth Agent v1.1.12 installs successfully (STATIC mode)
- Multiplayer connections work fine
- Repair and reinstall did NOT fix the issue

## Root Cause Analysis

`fastutil` (`it.unimi.dsi.fastutil`) should be bundled inside `HytaleServer.jar` (fat JAR). The `ClassNotFoundException` means the JVM's app classloader cannot find it despite it being in the JAR.

### Ruled Out

- **Wrapper issue**: Wrapper is working correctly (confirmed in logs)
- **UseCompactObjectHeaders**: Server also has `-XX:+IgnoreUnrecognizedVMOptions`, so unrecognized flags don't crash it
- **DualAuth Agent**: Works for all other users; agent installs successfully before the crash
- **Corrupted game files**: Repair/reinstall didn't help
- **ARM64/Parallels**: User is on standard Windows, not ARM

### Likely Cause

**CDS (Class Data Sharing) broken by bootstrap classloader modification.** DualAuth agent calls `appendToBootstrapClassLoaderSearch()` which triggers JVM warning: `"Sharing is only supported for boot loader classes because bootstrap classpath has been appended"`. This disables AppCDS for application classes. On some Windows systems, this breaks the classloader's ability to find classes (including fastutil) from the fat JAR.

This warning appears for ALL users, but only breaks classloading on some Windows systems — reason unknown.

### Other Possible Causes

1. **Antivirus interference** — AV blocking Java from reading classes out of JAR files
2. **File locking** — another process holding HytaleServer.jar open (Asentrix had stalled java.exe killed at launch)

## Potential Fix: `-Xshare:off` (testing Feb 27)

Disables CDS entirely, forcing standard classloading. User can add via launcher:
1. **Settings** → **Java Wrapper Configuration** → **Arguments to Inject**
2. Add `-Xshare:off` with **Server Only** condition
3. Retry singleplayer

Sent to affected users for testing — **awaiting results**.

If confirmed, should be added as default inject arg (server-only) in launcher config.

## Debugging Steps (for reference)

Most steps are impractical for F2P users:
- ~~Official Hytale singleplayer~~ — F2P users don't have official access
- ~~Try without DualAuth agent~~ — not possible, agent required for F2P token validation
- ~~Verify fastutil in JAR~~ — same JAR for all users, not a user-actionable step
- ~~Check JRE version~~ — bundled with launcher, same for all users

**Practical steps:**
1. **Add `-Xshare:off`** via wrapper inject args (server-only) — testing now
2. **Check antivirus** — add game directory to Windows Defender exclusions
3. **Check for stalled processes** — kill any leftover java.exe/HytaleServer before launch

## Update History

### Feb 24: `-XX:+UseCompactObjectHeaders` stripping removed from defaults
Stripping this flag did NOT fix the issue. The server already has `-XX:+IgnoreUnrecognizedVMOptions` so unrecognized flags are harmless. The flag was removed from default `stripFlags` in `backend/core/config.js`.

### Feb 27: Second user (Asentrix) reported, `-Xshare:off` sent for testing
Asentrix hit the same crash on Launcher v2.4.4. Unlike JAYED, no AOT cache errors — just the CDS sharing warning followed by fastutil ClassNotFoundException. This confirms the issue is not AOT-specific but related to CDS/classloader interaction with the DualAuth agent's bootstrap CL modification. Sent `-Xshare:off` workaround to affected users — awaiting results.

## Using the Java Wrapper to Strip JVM Flags

If a user needs to strip a specific JVM flag (e.g., for debugging or compatibility), they can do it via the launcher UI:

1. Open **Settings** → scroll to **Java Wrapper Configuration**
2. Under **JVM Flags to Remove**, type the flag (e.g. `-XX:+UseCompactObjectHeaders`) and click **Add**
3. The flag will be stripped from all JVM invocations at launch time
4. To inject custom arguments, use the **Arguments to Inject** section (with optional "Server Only" condition)
5. **Restore Defaults** resets to empty strip flags + `--disable-sentry` (server only)

The wrapper generates platform-specific scripts at launch time:
- **Windows**: `java-wrapper.bat` in `jre/latest/bin/`
- **macOS/Linux**: `java-wrapper` shell script in the same directory

Config is stored in `config.json` under `javaWrapperConfig`:
```json
{
  "javaWrapperConfig": {
    "stripFlags": ["-XX:+SomeFlag"],
    "injectArgs": [
      { "arg": "--some-arg", "condition": "server" },
      { "arg": "--other-arg", "condition": "always" }
    ]
  }
}
```

## Related

- Java wrapper config: `backend/core/config.js` (stripFlags / injectArgs)
- DualAuth Agent: v1.1.12, package `ws.sanasol.dualauth`
- Game version at time of reports: `2026.02.19-1a311a592`
- Log submission ID (Asentrix): `c88e7b71`
