Skip to content

Fix NRE in CompSuppressable.IsHunkering when pawn.CurJob is null - #4652

Open
WhiteGiverMa wants to merge 1 commit into
CombatExtended-Continued:Developmentfrom
WhiteGiverMa:fix/ishunkering-curjob-nre
Open

Fix NRE in CompSuppressable.IsHunkering when pawn.CurJob is null#4652
WhiteGiverMa wants to merge 1 commit into
CombatExtended-Continued:Developmentfrom
WhiteGiverMa:fix/ishunkering-curjob-nre

Conversation

@WhiteGiverMa

@WhiteGiverMa WhiteGiverMa commented Jul 4, 2026

Copy link
Copy Markdown

Changes

Add null-conditional access (pawn.CurJob?.def) in CompSuppressable.IsHunkering to prevent NullReferenceException when a pawn enters the hunkering recovery path with no current job.

Reasoning

CompSuppressable.IsHunkering has a recovery path that runs when a pawn has suppression buildup but isSuppressed == false (an abnormal but possible state). In this path, it checks if the pawn currently has a HunkerDown job by accessing pawn.CurJob.def. However, pawn.CurJob can be null when the pawn is idle or between jobs, causing NullReferenceException.

Stack trace:

Exception ticking XXX: System.NullReferenceException
  at CombatExtended.CompSuppressable.get_IsHunkering()
  at CombatExtended.CompTacticalManager.TryGiveTacticalJobs()
  at CombatExtended.CompTacticalManager.CompTickRare()
  at Verse.ThingWithComps.TickRare()
  at Verse.Pawn.Tick()

The same codebase already uses this null-check pattern in ExternalPawnDrafter.cs:11:

(pawn.CurJob == null || pawn.CurJob.def.playerInterruptible)

Alternatives

Could use pawn.CurJob != null && pawn.CurJob.def == ... instead of ?., but the null-conditional operator is more concise and already in use elsewhere in the CE codebase.

Testing

  • Compiles without warnings (dotnet build -c Release: 0 warnings, 0 errors)
  • Game runs without errors
  • (For compatibility patches) ...with and without patched mod loaded
  • Playtested a colony (45 days)

Add null-conditional access (pawn.CurJob?.def) to prevent
NullReferenceException when a pawn enters the hunkering recovery
path (has suppression but isSuppressed==false) with no current job.

The recovery path accesses pawn.CurJob.def to check for the
HunkerDown job, but CurJob can be null when the pawn is idle.
This matches the existing pattern in ExternalPawnDrafter.cs:11:
  (pawn.CurJob == null || pawn.CurJob.def.playerInterruptible)
@WhiteGiverMa
WhiteGiverMa requested review from a team as code owners July 4, 2026 18:53
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

You can download the rebuilt assembly for this PR here: https://combatextended.lp-programming.com/CombatExtended-28716298666.zip

@github-actions github-actions Bot added the Download in Comments This PR has a zipfile download available. label Jul 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Download in Comments This PR has a zipfile download available.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants