{"record":{"id":"da15ab24583638d3","repo":"alibaba/Sentinel","slug":"arrayadd-is-unavailable-if-minmax-has-been-cal","errorCode":null,"errorMessage":"arrayAdd() is unavailable if minMax() has been called","messagePattern":"arrayAdd\\(\\) is unavailable if minMax\\(\\) has been called","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sentinel-core/src/main/java/com/alibaba/csp/sentinel/eagleeye/StatEntryFunc.java","lineNumber":164,"sourceCode":"\n    @Override\n    public int getStatType() {\n        return 4;\n    }\n\n    @Override\n    public void count(long count) {\n        throw new IllegalStateException(\"count() is unavailable if minMax() has been called\");\n    }\n\n    @Override\n    public void countAndSum(long count, long value) {\n        throw new IllegalStateException(\"countAndSum() is unavailable if minMax() has been called\");\n    }\n\n    @Override\n    public void arrayAdd(long... values) {\n        throw new IllegalStateException(\"arrayAdd() is unavailable if minMax() has been called\");\n    }\n\n    @Override\n    public void arraySet(long... values) {\n        throw new IllegalStateException(\"arraySet() is unavailable if minMax() has been called\");\n    }\n\n    @Override\n    public void batchAdd(long... values) {\n        throw new IllegalStateException(\"batchAdd() is unavailable if minMax() has been called\");\n    }\n\n    @Override\n    public void minMax(long candidate, String ref) {\n        ValueRef lmax = max.get();\n        if (lmax.value <= candidate) {\n            final ValueRef cmax = new ValueRef(candidate, ref);\n            while (!max.compareAndSet(lmax, cmax) && (lmax = max.get()).value <= candidate) { ; }","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/alibaba/Sentinel/blob/a3f40ba8e900c8489bd520274739f17235a7721c/sentinel-core/src/main/java/com/alibaba/csp/sentinel/eagleeye/StatEntryFunc.java#L146-L182","documentation":"On StatEntryFuncMinMax, arrayAdd(long... values) throws IllegalStateException. The array-add strategy requires a fixed-length slot array; the min/max func only holds two single-value references (max and min), so array accumulation is structurally impossible.","triggerScenarios":"Calling arrayAdd(values) on an entry created with the minMax strategy — typically array-style reporting code applied to a latency min/max metric, or a config mismatch between metric type and emitter method.","commonSituations":"Array-based dashboards retrofitted onto min/max metrics. Config-driven metric types changed after emitters were written. Shared emitter code across heterogeneous metrics.","solutions":["Use minMax(candidate, ref) for min/max entries; use a dedicated array-type entry for arrayAdd.","Split the metric into two entries if both shapes are needed.","Gate the writer with a getStatType() check in shared emitters."],"exampleFix":"// before\nfunc.arrayAdd(v1, v2, v3); // minMax func -> throws\n\n// after\nfunc.minMax(v1, ref);","handlingStrategy":"type-guard","validationCode":"if (func.getStatType() == 4) { func.minMax(value, ref); } else { func.arrayAdd(values); }","typeGuard":"boolean isMinMax(StatEntryFunc f) { return f.getStatType() == 4; }","tryCatchPattern":null,"preventionTips":["Keep array-metric emitters and min/max emitters in separate classes.","Validate metric config type against the emitter at wiring time.","Add unit tests per metric name covering the write path."],"tags":["eagleeye","stat-func","api-misuse","illegal-state","min-max","array","sentinel"],"backgroundTag":null,"analyzedSha":"a3f40ba8e900c8489bd520274739f17235a7721c","analyzedAt":"2026-08-14T11:10:30.678Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}