From 40002b68465cece4e96efd7a4e5a6c5e5ce78b91 Mon Sep 17 00:00:00 2001 From: Arkesh Mishra <118651144+arkmish@users.noreply.github.com> Date: Mon, 19 Oct 2026 20:13:15 +0530 Subject: [PATCH] ZOOKEEPER-4377: KeeperException.create has NullPointerException when low version client requests the high version server Backport of apache/zookeeper 9f355f5a5 (released in 3.5.10/3.7.1/3.8.0). Code.get throws IllegalArgumentException for unknown codes and KeeperException.create reports the code, instead of an NPE. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/main/resources/markdown/zookeeperQuotas.md | 2 +- .../java/org/apache/zookeeper/KeeperException.java | 11 ++++++++--- .../apache/zookeeper/KeeperExceptionQuotaTest.java | 11 +++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/zookeeper-docs/src/main/resources/markdown/zookeeperQuotas.md b/zookeeper-docs/src/main/resources/markdown/zookeeperQuotas.md index 1ee6d17cf0e..7f3c2bf8d36 100644 --- a/zookeeper-docs/src/main/resources/markdown/zookeeperQuotas.md +++ b/zookeeper-docs/src/main/resources/markdown/zookeeperQuotas.md @@ -31,7 +31,7 @@ limitations under the License. ZooKeeper has both namespace and bytes quotas. You can use the ZooKeeperMain class to set up quotas. This fork backports the native quota enforcement released in Apache ZooKeeper 3.8.7 -(ZOOKEEPER-3301 and ZOOKEEPER-4219). Per-namespace quota metrics +(ZOOKEEPER-3301, ZOOKEEPER-4219, and ZOOKEEPER-4377). Per-namespace quota metrics (ZOOKEEPER-4211) are not included. Soft limits produce warnings; hard limits reject writes with `QuotaExceededException`. Both checks require the startup JVM property `-Dzookeeper.enforceQuota=true`, which defaults to diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/KeeperException.java b/zookeeper-server/src/main/java/org/apache/zookeeper/KeeperException.java index 876ead2ef95..f35f0401599 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/KeeperException.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/KeeperException.java @@ -154,7 +154,7 @@ public static KeeperException create(Code code) { return new TotalEphemeralLimitExceeded(); case OK: default: - throw new IllegalArgumentException("Invalid exception code"); + throw new IllegalArgumentException("Invalid exception code:" + code.code); } } @@ -439,10 +439,15 @@ public int intValue() { /** * Get the Code value for a particular integer error code * @param code int error code - * @return Code value corresponding to specified int code, or null + * @return Code value corresponding to specified int code + * @throws IllegalArgumentException if the client does not recognize the code */ public static Code get(int code) { - return lookup.get(code); + Code codeVal = lookup.get(code); + if (codeVal == null) { + throw new IllegalArgumentException("The current client version cannot lookup this code:" + code); + } + return codeVal; } } diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/KeeperExceptionQuotaTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/KeeperExceptionQuotaTest.java index a22b2c5abe8..921e1bd5300 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/KeeperExceptionQuotaTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/KeeperExceptionQuotaTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import org.apache.zookeeper.cli.CliWrapperException; import org.junit.Test; @@ -39,4 +40,14 @@ public void testEphemeralErrorDecoding() { assertTrue(error instanceof KeeperException.TotalEphemeralLimitExceeded); assertEquals("/session", error.getPath()); } + + @Test + public void testUnknownWireErrorIsExplicit() { + try { + KeeperException.create(KeeperException.Code.get(Integer.MIN_VALUE), "/unknown"); + fail("An unknown wire error must be reported explicitly"); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().contains(Integer.toString(Integer.MIN_VALUE))); + } + } }