Player Death System Troubleshooting Guide
Comprehensive troubleshooting guide for the player death system (overhauled in PR #1094, March 26, 2026).Quick Diagnosis
Symptom: Player stuck in death animation, never respawns
Likely Causes:- Death lock not cleared after respawn
- Database transaction deadlock (pre-PR #1094)
- Respawn timer not firing
- Death state desync between client and server
Symptom: Equipment duplicates on death
Likely Causes:- Post-transaction DB persist failed (equipment not cleared)
- Death lock not preventing reconnect inventory load
- Gravestone loot not properly cleared
Symptom: Items lost on death (not in gravestone or inventory)
Likely Causes:- Gravestone spawned but entity destroyed prematurely
- Ground items despawned before player could loot
- Death lock cleared before items recovered
System Architecture
Death Flow (Safe Zone)
Two-Phase Persist Pattern
Why? SQLite deadlocks on nested transactions. The death transaction callsclearEquipmentAndReturn() and clearInventoryImmediate(), which each try to open their own transactions.
Solution:
- Inside transaction: Clear in-memory state, skip DB persist
- After transaction: Persist to DB with retry queue
Persist Retry Queue
Purpose: Handle transient DB failures during post-transaction persist. Behavior:- Single retry per failure (no infinite loops)
- Bounded to 100 entries (prevents unbounded growth)
- Drained once per tick in
processPendingRespawns() - Emits
AUDIT_LOGevent on retry failure
Common Issues
Issue: Player respawns but kept items not returned
Diagnosis:itemsKeptOnDeathMap cleared before respawn- Death lock
keptItemsfield empty addItemDirect()failed (inventory full, DB error)
Issue: Gravestone shows duplicate items after looting
Diagnosis:CORPSE_EMPTYevent not firing (event lost)- Gravestone entity not destroyed after looting
lootItemsnot synced to client viamodify()
HeadstoneEntity.modify()now syncslootItemsfrom network dataPlayerDeathSystem.handleCorpseEmpty()destroys entity viaEntityManager- Tick-based expiration fallback if
CORPSE_EMPTYis lost
Issue: Death lock persists after respawn
Diagnosis:clearDeathLock()not called after respawnCORPSE_EMPTYevent never fired- Server crashed before lock cleared
Issue: Player respawns during active duel
Diagnosis:- Duel respawn guard not active (pre-PR #1094)
isPlayerInActiveDuel()returning false incorrectly
handleRespawnRequest()blocks respawn during active duelsinitiateRespawn()has defense-in-depth guard
Issue: Gravestone loot visible to all players
Diagnosis:HeadstoneEntity.getNetworkData()includeslootItems(pre-PR #1094)- Loot sent via broadcast instead of targeted packet
lootItemsstripped fromgetNetworkData()andserialize()- Only
lootItemCountis broadcast - Full loot data sent via targeted
corpseLootpacket on interaction
Monitoring & Alerting
Key Metrics
Death Lock Age:AUDIT_LOG Events
The death system emitsAUDIT_LOG events for ops visibility:
Event Types:
DEATH_LOCK_RECONNECT_BLOCK- Player reconnected with active death lock (crash recovery)DEATH_PERSIST_DESYNC- Equipment/inventory persist retry failed (possible item duplication)DEATH_PERSIST_RETRY_QUEUE_FULL- Retry queue full (DB persistently unavailable)
Configuration
Death Constants
Tuning Parameters
Respawn Timing:Testing
Unit Tests
DeathUtils.test.ts (51 tests):sanitizeKilledBy()- XSS, Unicode, injection, edge casessplitItemsForSafeDeath()- OSRS keep-3, stack handling, OOM regressionvalidatePosition()- Validation, clamping, invalid inputsisPositionInBounds()- Bounds checkingisValidPositionNumber()- Finite number validationgetItemValue()- Manifest lookup
- Duel guard blocks respawn
- Death processing race guard
- Tick-based respawn timing
- Persist retry queue drain
PLAYER_DIED→PLAYER_SET_DEADmigration
Integration Tests
PvPDeath.integration.test.ts:- Full death flow with real server
- Gravestone spawning and looting
- Kept items returned on respawn
- Death lock cleanup
- Gravestone TTL expiration
- Tick-based cleanup
- Item drop to ground after gravestone expires
- Immediate ground item drop
- No gravestone in wilderness
- All items dropped (no keep-3)
Recovery Procedures
Stuck Death Lock
Symptoms: Player can’t log in, or inventory is empty on login. Diagnosis:Duplicate Equipment
Symptoms: Player has duplicate items after death. Diagnosis:Orphaned Gravestone
Symptoms: Gravestone persists after looting, shows stale items. Diagnosis:EntityManager.destroyEntity(). Update to latest version.
Database Schema
death_locks Table
player_id: Player character ID (primary key)gravestone_id: Gravestone entity ID (empty until spawned)position_x/y/z: Death positionzone_type: “safe_area” or “wilderness”item_count: Number of dropped itemsitems: Dropped items (for gravestone)kept_items: Kept items (for respawn) - NEW in PR #1094killed_by: Killer name (sanitized)timestamp: Death timestamp (milliseconds)
Migration (PR #1094)
Event Reference
Deprecated Events
PLAYER_DIED (deprecated in PR #1094):
New Events (PR #1094)
PLAYER_SET_DEAD:
DEATH_RECOVERED:
AUDIT_LOG:
Performance Tuning
Tick-Based Respawn
Advantages:- Deterministic timing (no setTimeout drift)
- Server-authoritative (client can’t manipulate)
- Efficient (single tick handler for all players)
TickSystem not available (client-side), uses setTimeout.
Persist Retry Queue
Tuning:Gravestone Cleanup
Tick-Based Expiration:Security Considerations
Duel Escape Prevention
Exploit: Player could respawn during duel to escape with staked items. Fix (PR #1094):handleRespawnRequest()- Blocks manual respawn buttoninitiateRespawn()- Defense-in-depth guard
Position Validation
Exploit: Malicious client sends extreme position to teleport on death. Fix:Killer Name Sanitization
Exploit: Malicious killer name with XSS/injection payload. Fix:Related Documentation
- PlayerDeathSystem.ts - Main death orchestrator
- DeathUtils.ts - Pure utility functions
- DeathTypes.ts - Type definitions
- SafeAreaDeathHandler.ts - Safe zone handler
- WildernessDeathHandler.ts - Wilderness handler
- DeathStateManager.ts - Death lock persistence
- OSRS Wiki - Death - OSRS death mechanics reference
Changelog
March 26, 2026 (PR #1094)
- Complete rewrite of death pipeline
- Two-phase persist pattern (fixes SQLite deadlock)
- OSRS keep-3 system for safe zone deaths
- Gravestone privacy (loot hidden from broadcast)
- Death lock crash recovery with kept items
- Persist retry queue (bounded to 100 entries)
- Duel respawn guard (prevents escape exploit)
- Death processing guard (prevents respawn race)
- Event migration (
PLAYER_DIED→PLAYER_SET_DEAD/ENTITY_DEATH) - 61 new tests (DeathUtils + PlayerDeathFlow)
- 23 files changed, 2,574 additions, 566 deletions