{"record":{"id":"754751ef9aad1f09","repo":"apache/pulsar","slug":"bytes-must-be-0","errorCode":null,"errorMessage":"bytes must be >= 0","messagePattern":"bytes must be >= 0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/MemorySize.java","lineNumber":37,"sourceCode":"package org.apache.pulsar.client.api.v5.config;\n\n/**\n * A type-safe representation of a memory size in bytes.\n *\n * <p>Use the static factory methods to create instances from common units:\n * <pre>{@code\n * MemorySize.ofMegabytes(64)   // 64 MB\n * MemorySize.ofGigabytes(1)    // 1 GB\n * MemorySize.ofKilobytes(512)  // 512 KB\n * }</pre>\n *\n * @param bytes the size in bytes\n */\npublic record MemorySize(long bytes) {\n\n    public MemorySize {\n        if (bytes < 0) {\n            throw new IllegalArgumentException(\"bytes must be >= 0\");\n        }\n    }\n\n    private static final long KB = 1024;\n    private static final long MB = 1024 * KB;\n    private static final long GB = 1024 * MB;\n\n    /**\n     * Create a memory size from a number of bytes.\n     *\n     * @param bytes the size in bytes\n     * @return a {@link MemorySize} representing the specified number of bytes\n     */\n    public static MemorySize ofBytes(long bytes) {\n        return new MemorySize(bytes);\n    }\n\n    /**","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/MemorySize.java#L19-L55","documentation":"MemorySize is a record whose compact constructor validates that the byte count is non-negative; it represents sizes (batch limits, buffer sizes) where negative values are meaningless. Any attempt to construct MemorySize with a negative long throws IllegalArgumentException. This check also backs BatchingPolicy's maxSize validation.","triggerScenarios":"Calling new MemorySize(-1), MemorySize.ofBytes(-n), or any factory/conversion that receives a negative byte count; storing a 'remaining quota' that went negative directly into MemorySize.","commonSituations":"Subtraction-based accounting underflow; unit conversion mistakes (MiB vs bytes with overflow wrapping negative is rare but possible with huge longs); config values with a stray minus sign.","solutions":["Pass a non-negative byte count: new MemorySize(128 * 1024).","Fix the upstream computation and clamp: Math.max(0, bytes).","For 'unset' use Optional or omit the setting instead of a negative sentinel."],"exampleFix":"// before\nMemorySize size = new MemorySize(-1); // IllegalArgumentException: bytes must be >= 0\n\n// after\nMemorySize size = new MemorySize(128 * 1024);","handlingStrategy":"validation","validationCode":"if (bytes < 0) {\n    throw new IllegalArgumentException(\"bytes must be >= 0, got: \" + bytes);\n}\nMemorySize size = new MemorySize(bytes);","typeGuard":"static boolean isValidMemorySize(MemorySize s) { return s != null && s.bytes() >= 0; }","tryCatchPattern":"try {\n    size = new MemorySize(bytes);\n} catch (IllegalArgumentException e) {\n    log.warn(\"Negative size, clamping to 0\", e);\n    size = new MemorySize(0);\n}","preventionTips":["Clamp accounting arithmetic (limit - used) with Math.max(0, value) before constructing.","Never use negative sentinels for sizes; use Optional or omit the setting.","Check for long overflow in large unit conversions that could wrap negative."],"tags":["java","configuration","memory-size","record","illegal-argument"],"backgroundTag":"invalid-configuration-value","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}