{"record":{"id":"778917646b304a41","repo":"alibaba/Sentinel","slug":"countandsum-is-unavailable-if-minmax-has-been","errorCode":null,"errorMessage":"countAndSum() is unavailable if minMax() has been called","messagePattern":"countAndSum\\(\\) 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":159,"sourceCode":"    public Object[] getValues() {\n        ValueRef lmax = max.get();\n        ValueRef lmin = min.get();\n        return new Object[] {lmax.value, lmax.ref, lmin.value, lmin.ref};\n    }\n\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","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/alibaba/Sentinel/blob/a3f40ba8e900c8489bd520274739f17235a7721c/sentinel-core/src/main/java/com/alibaba/csp/sentinel/eagleeye/StatEntryFunc.java#L141-L177","documentation":"StatEntryFuncMinMax stores only max/min ValueRef pairs; it cannot accumulate a count or a sum, so countAndSum(long count, long value) throws IllegalStateException. The supported write method for this strategy is exclusively minMax(candidate, ref).","triggerScenarios":"Calling countAndSum(c, v) on an entry whose func is StatEntryFuncMinMax — e.g. latency-tracking code that tries to record both totals and extremes on one entry, or a writer selected by config that no longer matches the entry type.","commonSituations":"Teams want avg+min+max in one row and assume one entry can do all of it. Metric type changed in configuration. Copy-pasted aggregation code between different stat entries.","solutions":["Call minMax(candidate, ref) on min/max entries; put count/sum in a second entry.","Restructure the metric as two entries sharing the same keys so the output row still reads coherently.","Add a startup assertion that the configured entry type matches the writer method."],"exampleFix":"// before\nfunc.countAndSum(1, elapsed); // minMax entry -> throws\n\n// after\nminMaxFunc.minMax(elapsed, resource);\ncountFunc.countAndSum(1, elapsed);","handlingStrategy":"type-guard","validationCode":"if (func.getStatType() == 4) {\n    func.minMax(value, ref);\n} else {\n    func.countAndSum(1, value);\n}","typeGuard":"boolean isMinMax(StatEntryFunc f) { return f.getStatType() == 4; }","tryCatchPattern":null,"preventionTips":["Never assume one entry can hold count+sum+min+max; model them as separate entries.","Pair each entry creation with exactly one writer method in a recorder class.","Smoke-write each metric at startup."],"tags":["eagleeye","stat-func","api-misuse","illegal-state","min-max","sentinel"],"backgroundTag":null,"analyzedSha":"a3f40ba8e900c8489bd520274739f17235a7721c","analyzedAt":"2026-08-14T11:10:30.678Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}