{"record":{"id":"2dc01583a3818608","repo":"apache/druid","slug":"counter-increment-amount-must-be-non-negative-but","errorCode":null,"errorMessage":"Counter increment amount must be non-negative, but got value[%f] for metric[%s]. If this is valid, metric should be defined as a gauge instead of counter.","messagePattern":"Counter increment amount must be non-negative, but got value\\[(.+?)\\] for metric\\[(.+?)\\]\\. If this is valid, metric should be defined as a gauge instead of counter\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"extensions-contrib/prometheus-emitter/src/main/java/org/apache/druid/emitter/prometheus/PrometheusEmitter.java","lineNumber":187,"sourceCode":"          if (config.isAddHostAsLabel() && TAG_HOSTNAME.equals(labelName)) {\n            labelValues[i] = host;\n          } else if (config.isAddServiceAsLabel() && TAG_SERVICE.equals(labelName)) {\n            labelValues[i] = service;\n          } else if (extraLabels.containsKey(labelName)) {\n            labelValues[i] = config.getExtraLabels().get(labelName);\n          } else {\n            labelValues[i] = \"unknown\";\n          }\n        }\n      }\n\n      if (metric.getCollector() instanceof Counter) {\n        double metricValue = value.doubleValue();\n        if (metricValue >= 0) {\n          ((Counter) metric.getCollector()).labels(labelValues).inc(metricValue);\n          metric.resetLastUpdateTime(Arrays.asList(labelValues));\n        } else {\n          log.warn(\"Counter increment amount must be non-negative, but got value[%f] for metric[%s]. If this is valid, metric should be defined as a gauge instead of counter.\", metricValue, name);\n        }\n      } else if (metric.getCollector() instanceof Gauge) {\n        ((Gauge) metric.getCollector()).labels(labelValues).set(value.doubleValue());\n        metric.resetLastUpdateTime(Arrays.asList(labelValues));\n      } else if (metric.getCollector() instanceof Histogram) {\n        ((Histogram) metric.getCollector()).labels(labelValues)\n                                           .observe(value.doubleValue() / metric.getConversionFactor());\n        metric.resetLastUpdateTime(Arrays.asList(labelValues));\n      } else {\n        log.error(\"Unrecognized metric type [%s]\", metric.getCollector().getClass());\n      }\n    } else {\n      log.debug(\"Unmapped metric [%s]\", name);\n    }\n  }\n\n  private void pushMetric()\n  {","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-contrib/prometheus-emitter/src/main/java/org/apache/druid/emitter/prometheus/PrometheusEmitter.java#L169-L205","documentation":"Prometheus counters can only increase; the client library rejects negative inc(). When a Druid metric arrives with a negative value while the metric is defined as a Counter in the emitter's configured metrics list, the increment is skipped and this warning explains that the metric should be a Gauge if negative values are valid.","triggerScenarios":"Emitting a Druid metric whose value is negative while prometheus-emitter config maps that metric name to type 'counter' — e.g. lag or delta metrics that legitimately go negative, or buggy metric producers sending negative deltas.","commonSituations":"Kafka/Rabbit lag metrics temporarily negative due to clock/offset quirks; metrics like query/time deltas or queue depths misconfigured as counters; copying a metric config line as 'counter' when it should be 'gauge'.","solutions":["Change the metric's type from 'counter' to 'gauge' in the prometheus emitter's metrics configuration if negative values are legitimate","Check the emitting component for a bug producing negative values where only non-negative makes sense","Verify which metric name the warning names and confirm its Druid semantics before reclassifying","If the value must be a counter, clamp or track deltas instead of absolute values"],"exampleFix":"// before (emitter JSON config)\n{\"name\": \"ingest/events/lag\", \"type\": \"counter\"}\n// after\n{\"name\": \"ingest/events/lag\", \"type\": \"gauge\"}","handlingStrategy":"validation","validationCode":"if (value < 0 && isCounterMetric(metricName)) {\n  log.warn(\"Skipping negative value %f for counter %s\", value, metricName);\n  return;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Define any metric that can go negative as 'gauge' in emitter config","Audit metric definitions against Druid metric semantics","Clamp deltas or use gauges for lag-like metrics"],"tags":["prometheus","metrics","counter","negative-value"],"backgroundTag":"invalid-argument-value","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}