Skip to content

fix(Scurrius): read giant rat name once to avoid NPE in rat query (1.0.4) - #641

Merged
chsami merged 1 commit into
developmentfrom
claude/err-scurrius-giant-rat-name-toctou-npe
Oct 15, 2026
Merged

chsami merged 1 commit into
developmentfrom
claude/err-scurrius-giant-rat-name-toctou-npe

Conversation

@chsami

@chsami chsami commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Problem

Client error telemetry group 2212 (ScurriusPlugin 1.0.2, Microbot 2.6.33, 1 occurrence in the last 7 days) reports:

java.lang.NullPointerException: Cannot invoke "String.toLowerCase()" because the return value of "...Rs2NpcModel.getName()" is null
  at ScurriusScript.lambda$run$1:196
  at AbstractEntityQueryable.nearest:239
  at ScurriusScript.lambda$run$3:198

The exception ends the whole Scurrius tick.

Root cause

The giant-rat query filter was n.getName() != null && n.getName().toLowerCase().contains("giant rat") && !n.getNpc().isDead(). It calls getName() twice. If the rat despawns or its composition changes between the null check and the second call, the second call returns null and toLowerCase() throws. The same line is still on development (1.0.3, line 193).

Change

  • ScurriusScript: the query now uses .where(ScurriusScript::isLiveGiantRat). The new static helper isLiveGiantRat(Rs2NpcModel) reads the name once into a local, then checks for null, checks for "giant rat" (case-insensitive) and checks that the NPC is not dead.
  • ScurriusPlugin version goes from 1.0.3 to 1.0.4.
  • ScurriusScriptTest: 3 new Mockito tests:
    • getName() returns "Giant rat" first and null second. The helper returns true and getName() is called exactly once. This would throw with the old logic.
    • a null name is rejected.
    • a dead giant rat and a non-rat NPC are both rejected.

Validation

./gradlew test --tests 'net.runelite.client.plugins.microbot.scurrius.*' --tests 'net.runelite.client.plugins.microbot.PluginManifestVersionTest' -PpluginList=ScurriusPlugin gave BUILD SUCCESSFUL:

  • ScurriusScriptTest: 8 tests, 0 failures
  • PluginManifestVersionTest: 1 test, 0 failures

Known gaps

  • Not tested live against a running client.
  • Other Hub plugins use the same double-getName() pattern in cache queries, for example DelvePrayerHelperScript:53 and :126, EnsouledHeadSlayerScript:140 and SalvagingScript:1460. They are out of scope for this per-error fix and are candidates for a follow-up sweep to withNameContains or a single-read local.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV

…0.4)

The giant-rat query predicate called getName() twice; when the NPC
despawned between the null check and toLowerCase() the second call
returned null and the NPE aborted the Scurrius tick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV
@chsami
chsami merged commit 0cab914 into development Oct 15, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant