{"record":{"id":"4f91820a247bdbe8","repo":"apache/dubbo","slug":"negative-initial-size-size","errorCode":null,"errorMessage":"Negative initial size: ${size}","messagePattern":"Negative initial size: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/io/UnsafeByteArrayOutputStream.java","lineNumber":38,"sourceCode":"import java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\n\n/**\n * UnsafeByteArrayOutputStream.\n */\npublic class UnsafeByteArrayOutputStream extends OutputStream {\n    protected byte[] mBuffer;\n\n    protected int mCount;\n\n    public UnsafeByteArrayOutputStream() {\n        this(32);\n    }\n\n    public UnsafeByteArrayOutputStream(int size) {\n        if (size < 0) {\n            throw new IllegalArgumentException(\"Negative initial size: \" + size);\n        }\n        mBuffer = new byte[size];\n    }\n\n    @Override\n    public void write(int b) {\n        int newCount = mCount + 1;\n        if (newCount > mBuffer.length) {\n            mBuffer = Bytes.copyOf(mBuffer, Math.max(mBuffer.length << 1, newCount));\n        }\n        mBuffer[mCount] = (byte) b;\n        mCount = newCount;\n    }\n\n    @Override\n    public void write(byte[] b, int off, int len) {\n        if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {\n            throw new IndexOutOfBoundsException();","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/io/UnsafeByteArrayOutputStream.java#L20-L56","documentation":"Thrown by the UnsafeByteArrayOutputStream(int size) constructor when `size` is negative. The constructor allocates `new byte[size]`, which the JVM would reject with NegativeArraySizeException; Dubbo pre-validates and raises IllegalArgumentException(\"Negative initial size: \" + size) with a clearer message. The no-arg constructor delegates to this(32) and never triggers it.","triggerScenarios":"Calling new UnsafeByteArrayOutputStream(size) with size < 0; passing a capacity computed as a - b where a < b; passing a length/size field that was never initialized (default may be 0, but a -1 sentinel triggers it).","commonSituations":"A configured/derived initial capacity that went negative due to an arithmetic underflow; passing a 'remaining bytes' value that is negative when the buffer is already larger; copy-paste of -1 default sentinel into a capacity argument.","solutions":["Use the no-arg constructor new UnsafeByteArrayOutputStream() (defaults to 32) when you have no concrete capacity estimate.","Clamp the capacity: new UnsafeByteArrayOutputStream(Math.max(0, computedSize)).","Precondition the producer of the size value so a negative capacity is surfaced at its source."],"exampleFix":"// before\nnew UnsafeByteArrayOutputStream(expected - current); // negative when current > expected\n// after\nnew UnsafeByteArrayOutputStream(Math.max(0, expected - current));","handlingStrategy":"validation","validationCode":"int cap = Math.max(0, expected - current);\nUnsafeByteArrayOutputStream out = new UnsafeByteArrayOutputStream(cap);","typeGuard":null,"tryCatchPattern":"try {\n    new UnsafeByteArrayOutputStream(size);\n} catch (IllegalArgumentException e) {\n    new UnsafeByteArrayOutputStream(); // fall back to default cap of 32\n}","preventionTips":["Use the no-arg constructor when you have no concrete capacity estimate.","Clamp computed capacities with Math.max(0, value).","Never pass a -1 sentinel as a capacity."],"tags":["stream","io","initialization","validation","dubbo-common"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}