Bug: Print exception message without stacktrace when nodetool commands fail on probe.getOwnershipWithPort()
Status: Resolved
Priority: Low
Resolution: Fixed
Created: 29/Nov/22 17:12
Resolved: 06/Dec/22 11:58

When status, ring or describecluster nodetool commands are executed while a node which is queried is not fully bootstrapped / started, it can throw this exception:
{code:java}
cassandra_node_4  | error: No nodes present in the cluster. Has this node finished starting up?
cassandra_node_4  | -- StackTrace --
cassandra_node_4  | java.lang.RuntimeException: No nodes present in the cluster. Has this node finished starting up?
cassandra_node_4  | 	at org.apache.cassandra.dht.Murmur3Partitioner.describeOwnership(Murmur3Partitioner.java:303)
cassandra_node_4  | 	at org.apache.cassandra.service.StorageService.getOwnershipWithPort(StorageService.java:5751)
cassandra_node_4  | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
cassandra_node_4  | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
cassandra_node_4  | 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
cassandra_node_4  | 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
cassandra_node_4  | 	at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
cassandra_node_4  | 	at jdk.internal.reflect.GeneratedMethodAccessor7.invoke(Unknown Source)
cassandra_node_4  | 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
cassandra_node_4  | 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
cassandra_node_4  | 	at java.base/sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:260)
cassandra_node_4  | 	at java.management/com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:112)
cassandra_node_4  | 	at java.management/com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:46)
cassandra_node_4  | 	at java.management/com.sun.jmx.mbeanserver.MBeanIntrospector.invokeM(MBeanIntrospector.java:237)
cassandra_node_4  | 	at java.management/com.sun.jmx.mbeanserver.PerInterface.getAttribute(PerInterface.java:83)
cassandra_node_4  | 	at java.management/com.sun.jmx.mbeanserver.MBeanSupport.getAttribute(MBeanSupport.java:206)
cassandra_node_4  | 	at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getAttribute(DefaultMBeanServerInterceptor.java:641)
cassandra_node_4  | 	at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.getAttribute(JmxMBeanServer.java:678)
cassandra_node_4  | 	at java.management/com.sun.jmx.remote.security.MBeanServerAccessController.getAttribute(MBeanServerAccessController.java:320)
cassandra_node_4  | 	at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1443)
cassandra_node_4  | 	at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1307)
cassandra_node_4  | 	at java.base/java.security.AccessController.doPrivileged(Native Method)
cassandra_node_4  | 	at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1406)
cassandra_node_4  | 	at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.getAttribute(RMIConnectionImpl.java:637)
cassandra_node_4  | 	at java.base/jdk.internal.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
cassandra_node_4  | 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
cassandra_node_4  | 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
cassandra_node_4  | 	at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
cassandra_node_4  | 	at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
cassandra_node_4  | 	at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
cassandra_node_4  | 	at java.base/java.security.AccessController.doPrivileged(Native Method)
cassandra_node_4  | 	at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
cassandra_node_4  | 	at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
cassandra_node_4  | 	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
cassandra_node_4  | 	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
cassandra_node_4  | 	at java.base/java.security.AccessController.doPrivileged(Native Method)
cassandra_node_4  | 	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
cassandra_node_4  | 	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
cassandra_node_4  | 	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
cassandra_node_4  | 	at java.base/java.lang.Thread.run(Thread.java:829)

{code}
The message as such is ok, it is more about the way we inform a user. There should not be stacktrace visible. Why it should? As a user I am not interested in that. All I want to see is one-liner about what happened.

In the code, for example for "status", look at this (1). When line 77 fails, it will go to the catch block and there is probe.getOwnershipWithPort() called. However, when that one fails (as shown above), that exception propagates to nodetool which will eventually log it with stacktrace as well. We should wrap this one more time and write exception message only and exit(1).

(1) [https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/tools/nodetool/Status.java#L75-L89]