
Logs, troubleshooting and performance
When something goes wrong the log almost always says why. This page lists where to look, the messages you are most likely to see, the usual causes, and how to keep a busy server smooth.
Where the logs are
| File | Contents |
|---|---|
logs/server.log | Main log (name from [logging] file). Rotated at max_bytes (16 MB) keeping backup_count (3) old files. Also printed to the console when console = true. |
logs/server.fault.log | Native crash stack traces (named after the log file). |
logs/anticheat.jsonl | Anti-cheat suspicion report, one JSON object per flagged player. |
bans.json | Current bans. |
state/round-results.sqlite3 | AoSPlay round results waiting for upload. |
/data/logs/… | The same files inside the Docker volume; docker logs shows the console. |
Every 10 seconds the server logs a tick stats: line with the average and maximum tick time and how many ticks took over 10 ms. At 60 Hz a tick has about 16.7 ms; a healthy server stays well below that. Set [logging] level = "DEBUG" only while investigating, and keep packet_trace off — it produces huge logs.
Messages you may see
| Log message | Meaning and fix |
|---|---|
In-game /admin login is DISABLED: … | The admin password is changeme, empty or under 12 characters. Set a real one and restart. |
Warning: Failed to load config from … (console only) | TOML syntax error or a BOM. The server is running on defaults. Fix the file (save as UTF-8 without BOM) and restart. |
game.default_mode '…' is not a registered game mode | Typo in the mode. The message lists every accepted name. |
Cannot start BattleSpades: UDP port 27015 is already in use or reserved | Another server (or an old one still running) holds the port. Stop it, change [server] port, or start with --port. |
AoS Revival master disabled: AOS_MASTER_WRITE_TOKEN is not set | Not listed on AoSPlay because no token is in the environment. Harmless for private servers. |
Revival heartbeat failed: … | AoSPlay rejected or could not be reached. Check the token, public_host, and that the registration is active (not pending). |
revival server_id must equal public_host:public_port | [revival] server_id (or AOS_SERVER_ID) does not match the host and port. Leave it blank to derive it. |
[network] timeout_ms is ignored … / [world] water_level/water_damage are ignored | Old keys with no effect. Remove them from your config. |
[weapons] … ignored: damage comes from the retail per-weapon tables / [world] map_size_x=… ignored | Deprecated keys: damage uses the retail weapon tables and maps are always 512 × 512 × 240. Remove the [weapons] table and the map_size_* keys. |
[server] name … is longer than the retail limit of 31 characters | Clients will see the shortened name. |
Retail catalogue lists <Map> as invalid for mode <m> | That map is not meant for this mode; it was skipped or will play oddly. |
Rejected banned client … | A banned address tried to connect. |
conduct kick player=… name=… reason=… | A grief or AFK kick happened. |
Steam master logon complete: steam_id=… | Steam listing works (only with [steam] enabled). |
BattleSpades container configuration error: … | A Docker environment variable is invalid or the admin password is missing. |
Common problems
Nobody can join from the internet
- Join from the host itself (
127.0.0.1:<port>). If that fails, the server is not running or uses another port — read the log. - Join from another device on the LAN. If that fails, the operating-system firewall blocks UDP.
- Join from another internet connection. If only this fails, check the router forward (UDP, correct LAN IP) or the cloud security group, and whether your provider uses CGNAT.
- Run
python deploy/a2s_probe.py --host <public-ip> --port <port>from outside to test the socket directly.
Players are refused as out of date
[network] require_protocol_version only admits protocol-168 clients (retail, non-Steam and the revival client all qualify). Older or unrelated clients get the retail client/server-out-of-date message.
The server is not on the AoSPlay list
- Is
AOS_MASTER_WRITE_TOKENset in the server's environment (not inconfig.toml)? - Is
[revival] enabled = trueandpublic_hostyour public IP (not127.0.0.1)? - Did registration end
status=active/verified=true? A pending registration is not listed; re-verify after fixing the port. - Heartbeats must come from the registered address. A server that moved to a new IP or port needs a new registration.
Team names show “Missing string …”
[teams] team1_name/team2_name must be client string IDs (TEAM1_COLOR, TEAM2_COLOR), not literal text.
Rebuilding fails on Windows
“Permission denied” or “file in use” during setup.py build_ext means a server process still has the compiled modules loaded. Stop every running instance first (check Task Manager for leftover python.exe).
Performance tips
- Keep
tick_rate = 60and every[debug]value as shipped. Keeppacket_trace,debug_parity,debug_selfrowandmovement_debug_captureoff. - Watch
tick stats: a risingmaxor manyslow(>10ms)ticks means the host is overloaded — fewer instances per core, fewer bots, or a faster CPU. - Memory depends mostly on the map. On small hosts prefer lighter rotations and fewer bots; the
processbot worker costs more memory thanthreadbut isolates crashes. - Bots: lower
perception_hz/decision_hzormax_botsif bot work shows up in the subsystem timings. - Keep
max_playersrealistic. 24 is the retail-tested ceiling; more players means more world updates per tick. - Leave the
[network]budgets alone unless a specific log message points at one; they bound worst-case work so a flood cannot stall the tick. - Host close to your players: lag compensation hides moderate latency, but it rewinds at most
lag_compensation_max_ms(250 ms).
Getting help
Ask on the community Discord or open an issue on GitHub (opens in a new tab). Include the output of --version and --check, the relevant part of logs/server.log, how you run the server (portable, source or Docker, and OS), and your config.toml with the admin password and tokens removed.
Common questions
The server window closes immediately.+
Start it from a terminal (PowerShell or bash) so the error stays visible, or read logs/server.log. Most often it is a port conflict or a config validation error.
How do I make logs smaller?+
Lower [logging] max_bytes and backup_count, keep level = "INFO", and turn console off for background services.


