[ 
https://issues.apache.org/jira/browse/CASSANDRA-21491?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Thomas Steinmaurer updated CASSANDRA-21491:
-------------------------------------------
    Description: 
With Cassandra 4.1.11, from time to time we see the following NPE in production:

{code:java}
ERROR [Messaging-EventLoop-3-9] 2026-07-07 14:31:19,408 
InboundMessageHandler.java:298 - 
/10.244.123.131:7000->/10.244.18.26:7000-LARGE_MESSAGES-24ff2250 unexpected 
exception caught while processing inbound messages; terminating connection
java.lang.NullPointerException: null
        at 
org.apache.cassandra.metrics.ClientMetrics.unpauseConnection(ClientMetrics.java:91)
        at 
org.apache.cassandra.net.AbstractMessageHandler.onReserveCapacityRegained(AbstractMessageHandler.java:314)
        at 
org.apache.cassandra.net.AbstractMessageHandler.onGlobalReserveCapacityRegained(AbstractMessageHandler.java:289)
        at 
org.apache.cassandra.net.AbstractMessageHandler.access$1600(AbstractMessageHandler.java:134)
        at 
org.apache.cassandra.net.AbstractMessageHandler$WaitQueue$Ticket.reactivateHandler(AbstractMessageHandler.java:792)
        at 
org.apache.cassandra.net.AbstractMessageHandler$WaitQueue$Ticket.access$1200(AbstractMessageHandler.java:759)
        at 
org.apache.cassandra.net.AbstractMessageHandler$WaitQueue$ReactivateHandlers.run(AbstractMessageHandler.java:740)
        at 
io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
        at 
io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
        at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:384)
        at 
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at 
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at 
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Unknown Source)
{code}

Throwing Claude (Sonnet 4.6) on it, I get the following (can't judge, if this 
makes sense):

---
Root Cause

ClientMetrics.pausedConnections is null when unpauseConnection() is called for 
inter-node connections.

The crash chain:

1. pausedConnections is only initialized in ClientMetrics.init() 
(ClientMetrics.java:145), which is called from NativeTransportService.java:120 
— i.e., only when the CQL native transport starts up.
2. Inter-node messaging (port 7000) starts earlier than the native transport 
during Cassandra startup. InboundMessageHandler extends AbstractMessageHandler 
and handles these connections.
3. AbstractMessageHandler.onReserveCapacityRegained() (line 314) 
unconditionally calls ClientMetrics.instance.unpauseConnection() — for both CQL 
client connections (correct) and inter-node LARGE_MESSAGES connections (wrong).
4. If a LARGE_MESSAGE inter-node connection gets throttled due to reserve 
capacity pressure and then the capacity is regained, this code path fires 
before ClientMetrics.init() has run → pausedConnections is still null → NPE.

---
Fix

The minimal, targeted fix is to initialize pausedConnections at field 
declaration rather than lazily inside init():

Claude proposes the following code change:

 !image-2026-07-08-10-20-27-313.png! 




  was:
With Cassandra 4.1.11, from time to time we see the following NPE in production:

{code:java}
ERROR [Messaging-EventLoop-3-9] 2026-07-07 14:31:19,408 
InboundMessageHandler.java:298 - 
/10.244.123.131:7000->/10.244.18.26:7000-LARGE_MESSAGES-24ff2250 unexpected 
exception caught while processing inbound messages; terminating connection
java.lang.NullPointerException: null
        at 
org.apache.cassandra.metrics.ClientMetrics.unpauseConnection(ClientMetrics.java:91)
        at 
org.apache.cassandra.net.AbstractMessageHandler.onReserveCapacityRegained(AbstractMessageHandler.java:314)
        at 
org.apache.cassandra.net.AbstractMessageHandler.onGlobalReserveCapacityRegained(AbstractMessageHandler.java:289)
        at 
org.apache.cassandra.net.AbstractMessageHandler.access$1600(AbstractMessageHandler.java:134)
        at 
org.apache.cassandra.net.AbstractMessageHandler$WaitQueue$Ticket.reactivateHandler(AbstractMessageHandler.java:792)
        at 
org.apache.cassandra.net.AbstractMessageHandler$WaitQueue$Ticket.access$1200(AbstractMessageHandler.java:759)
        at 
org.apache.cassandra.net.AbstractMessageHandler$WaitQueue$ReactivateHandlers.run(AbstractMessageHandler.java:740)
        at 
io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
        at 
io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
        at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:384)
        at 
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at 
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at 
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Unknown Source)
{code}

Throwing Claude (Sonnet 4.6) on it, I get the following:

---
Root Cause

ClientMetrics.pausedConnections is null when unpauseConnection() is called for 
inter-node connections.

The crash chain:

1. pausedConnections is only initialized in ClientMetrics.init() 
(ClientMetrics.java:145), which is called from NativeTransportService.java:120 
— i.e., only when the CQL native transport starts up.
2. Inter-node messaging (port 7000) starts earlier than the native transport 
during Cassandra startup. InboundMessageHandler extends AbstractMessageHandler 
and handles these connections.
3. AbstractMessageHandler.onReserveCapacityRegained() (line 314) 
unconditionally calls ClientMetrics.instance.unpauseConnection() — for both CQL 
client connections (correct) and inter-node LARGE_MESSAGES connections (wrong).
4. If a LARGE_MESSAGE inter-node connection gets throttled due to reserve 
capacity pressure and then the capacity is regained, this code path fires 
before ClientMetrics.init() has run → pausedConnections is still null → NPE.

---
Fix

The minimal, targeted fix is to initialize pausedConnections at field 
declaration rather than lazily inside init():

Claude proposes the following code change:

 !image-2026-07-08-10-20-27-313.png! 





> NPE in ClientMetrics.unpauseConnectionClient
> --------------------------------------------
>
>                 Key: CASSANDRA-21491
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-21491
>             Project: Apache Cassandra
>          Issue Type: Bug
>            Reporter: Thomas Steinmaurer
>            Priority: Normal
>         Attachments: image-2026-07-08-10-20-27-313.png
>
>
> With Cassandra 4.1.11, from time to time we see the following NPE in 
> production:
> {code:java}
> ERROR [Messaging-EventLoop-3-9] 2026-07-07 14:31:19,408 
> InboundMessageHandler.java:298 - 
> /10.244.123.131:7000->/10.244.18.26:7000-LARGE_MESSAGES-24ff2250 unexpected 
> exception caught while processing inbound messages; terminating connection
> java.lang.NullPointerException: null
>       at 
> org.apache.cassandra.metrics.ClientMetrics.unpauseConnection(ClientMetrics.java:91)
>       at 
> org.apache.cassandra.net.AbstractMessageHandler.onReserveCapacityRegained(AbstractMessageHandler.java:314)
>       at 
> org.apache.cassandra.net.AbstractMessageHandler.onGlobalReserveCapacityRegained(AbstractMessageHandler.java:289)
>       at 
> org.apache.cassandra.net.AbstractMessageHandler.access$1600(AbstractMessageHandler.java:134)
>       at 
> org.apache.cassandra.net.AbstractMessageHandler$WaitQueue$Ticket.reactivateHandler(AbstractMessageHandler.java:792)
>       at 
> org.apache.cassandra.net.AbstractMessageHandler$WaitQueue$Ticket.access$1200(AbstractMessageHandler.java:759)
>       at 
> org.apache.cassandra.net.AbstractMessageHandler$WaitQueue$ReactivateHandlers.run(AbstractMessageHandler.java:740)
>       at 
> io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
>       at 
> io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
>       at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:384)
>       at 
> io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
>       at 
> io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
>       at 
> io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
>       at java.base/java.lang.Thread.run(Unknown Source)
> {code}
> Throwing Claude (Sonnet 4.6) on it, I get the following (can't judge, if this 
> makes sense):
> ---
> Root Cause
> ClientMetrics.pausedConnections is null when unpauseConnection() is called 
> for inter-node connections.
> The crash chain:
> 1. pausedConnections is only initialized in ClientMetrics.init() 
> (ClientMetrics.java:145), which is called from 
> NativeTransportService.java:120 — i.e., only when the CQL native transport 
> starts up.
> 2. Inter-node messaging (port 7000) starts earlier than the native transport 
> during Cassandra startup. InboundMessageHandler extends 
> AbstractMessageHandler and handles these connections.
> 3. AbstractMessageHandler.onReserveCapacityRegained() (line 314) 
> unconditionally calls ClientMetrics.instance.unpauseConnection() — for both 
> CQL client connections (correct) and inter-node LARGE_MESSAGES connections 
> (wrong).
> 4. If a LARGE_MESSAGE inter-node connection gets throttled due to reserve 
> capacity pressure and then the capacity is regained, this code path fires 
> before ClientMetrics.init() has run → pausedConnections is still null → NPE.
> ---
> Fix
> The minimal, targeted fix is to initialize pausedConnections at field 
> declaration rather than lazily inside init():
> Claude proposes the following code change:
>  !image-2026-07-08-10-20-27-313.png! 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to