{"id":"4b3d9abbc08d58e5","repo":"apache/kafka","slug":"values-less-than-0-0-not-accepted","errorCode":null,"errorMessage":"Values less than 0.0 not accepted.","messagePattern":"Values less than 0\\.0 not accepted\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/metrics/stats/Histogram.java","lineNumber":207,"sourceCode":"        }\n\n        public int bins() {\n            return this.bins;\n        }\n\n        public double fromBin(int b) {\n            if (b > this.bins - 1) {\n                return Float.POSITIVE_INFINITY;\n            } else if (b < 0.0000d) {\n                return Float.NEGATIVE_INFINITY;\n            } else {\n                return this.scale * (b * (b + 1.0)) / 2.0;\n            }\n        }\n\n        public int toBin(double x) {\n            if (x < 0.0d) {\n                throw new IllegalArgumentException(\"Values less than 0.0 not accepted.\");\n            } else if (x > this.max) {\n                return this.bins - 1;\n            } else {\n                return (int) (-0.5 + 0.5 * Math.sqrt(1.0 + 8.0 * x / this.scale));\n            }\n        }\n    }\n}","sourceCodeStart":189,"sourceCodeEnd":215,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/metrics/stats/Histogram.java#L189-L215","documentation":"Thrown by `LinearBinScheme.toBin(double x)` when a negative value is recorded. Linear binning assumes a non-negative domain starting at 0 and uses `Math.sqrt(1.0 + 8.0 * x / scale)` to invert the bin-width formula; negative x breaks the inversion. Kafka rejects negative inputs rather than silently clamping or returning a malformed bin index.","triggerScenarios":"Recording a negative value into a Histogram backed by a LinearBinScheme: `histogram.record(-1.0)`. Indirectly via a `Percentiles` with `BucketSizing.LINEAR` whose Sensor records a negative sample, or via `Frequencies` constructed with a ConstantBinScheme (no—Constant allows negatives); specifically only LinearBinScheme.toBin rejects negatives.","commonSituations":"A sensor records latency deltas or counter deltas that go negative due to clock skew, reset, or counter wraparound. Feeding raw gauge values (e.g. temperature in Celsius, signed integers) into a Percentiles metric configured with LINEAR bucketing. Reusing a percentile metric built for sizes/counts (always >=0) for a signed signal.","solutions":["Clamp or filter negative values before recording them into the Sensor (record `Math.max(0, value)`).","If the signal is genuinely signed, switch to `BucketSizing.CONSTANT` with a `min` below the lowest expected value.","Fix upstream clock skew or counter resets so deltas never go negative."],"exampleFix":"// before\nsensor.record(deltaMs); // deltaMs can be negative on clock skew\n\n// after\nsensor.record(Math.max(0.0, deltaMs));","handlingStrategy":"validation","validationCode":"// LinearBinScheme.toBin throws on x < 0.0, reached via Histogram.record / Sensor.record\nif (value < 0.0d) {\n    throw new IllegalArgumentException(\n        \"LinearBinScheme does not accept negative values: \" + value);\n}\nhistogram.record(value);","typeGuard":null,"tryCatchPattern":"try {\n    histogram.record(value);\n} catch (IllegalArgumentException e) {\n    // \"Values less than 0.0 not accepted.\"\n    // Only LinearBinScheme is affected; ConstantBinScheme tolerates negatives.\n    histogram.record(Math.max(0.0d, value));\n}","preventionTips":["LinearBinScheme is the only built-in BinScheme that rejects negatives; confirm which scheme a Histogram uses before recording.","If your metric can legitimately go negative, use ConstantBinScheme with an appropriate min instead of LinearBinScheme.","Sanitize/clamp values at the Sensor recording boundary so a stray negative never reaches the histogram."],"tags":["metrics","histogram","percentiles","linear-binning","validation","java"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}