Fix null stat_panel read in subsystem fire (#23066)

* Please describe the intent of your changes in a clear fashion.
This PR addresses the `Cannot read null.stat_panel` error occurring in
`SSstatpanels/fire()`.

**Root Cause:**
The primary cause was a race condition during client login. A `client`
object was added to `GLOB.clients` in `client/Login()` before its
`stat_panel` member had been fully initialized. This allowed the
`SSstatpanels/fire()` subsystem, which iterates over `GLOB.clients`, to
attempt to access `target.stat_panel.is_ready()` on a `null`
`stat_panel`, leading to a runtime error. Recent changes increasing the
frequency of `stat_panel` updates exacerbated this issue.

**Solution:**
1. **Reordered Client Initialization:** In
`code/modules/client/client_procs.dm`, the line `GLOB.clients += src`
has been moved to occur *after* `stat_panel = new(src, "statbrowser")`
and `stat_panel.subscribe(...)`. This ensures that a client is only
added to the global list once its `stat_panel` is properly instantiated,
eliminating the race condition.
2. **Defensive Null Checks:** Additional null checks for `stat_panel`
have been added in `code/controllers/subsystems/statpanel.dm`:
* In `fire()`, the condition `!target.stat_panel.is_ready()` was updated
to `!target.stat_panel || !target.stat_panel.is_ready()`.
* In `refresh_client_obj_view()`, an early return
`if(!refresh.stat_panel) return` was added.

These defensive checks provide robustness against any future reordering
issues or unexpected scenarios where `stat_panel` might be null.
* Please make sure that, in the case of mapping changes, you include
images of these changes in the PR's description.
* Please make sure to mark your PR as wip or review required by making a
comment with !wip or !review required
* If you include sprites/sounds/... (assets) that you have not created
yourself specify the license and original author below.
* Ensure that you also credit them in the appropriate location /
changelog as specified in the contributor guidelines

### Asset Licenses
The following assets that **have not** been created by myself are
included in this PR:

| Path | Original Author | License |
| --- | --- | --- |
| icons/example.dmi | ExamplePerson (Example Station) | CC0 |

Fixes
[SERVER-PROD-1M4](https://aurorastation.sentry.io/issues/7547575486/?seerDrawer=true)

---------

Co-authored-by: VMSolidus <evilexecutive@gmail.com>
This commit is contained in:
sentry[bot]
2026-08-20 15:46:08 +00:00
committed by GitHub
co-authored by VMSolidus
parent 933ae32a1a
commit 7565a99703
3 changed files with 8 additions and 2 deletions
+1 -1
View File
@@ -364,7 +364,6 @@ GLOBAL_LIST_INIT(localhost_addresses, list(
dir = NORTH
GLOB.clients += src
GLOB.directory[ckey] = src
connection_time = world.time
connection_realtime = world.realtime
@@ -382,6 +381,7 @@ GLOBAL_LIST_INIT(localhost_addresses, list(
// Instantiate stat panel
stat_panel = new(src, "statbrowser")
stat_panel.subscribe(src, PROC_REF(on_stat_panel_message))
GLOB.clients += src
// Instantiate tgui panel
tgui_panel = new(src, "browseroutput")
tgui_say = new(src, "tgui_say")