{"record":{"id":"ee98138c342d5efd","repo":"alibaba/Sentinel","slug":"arrayset-is-unavailable-if-minmax-has-been-cal","errorCode":null,"errorMessage":"arraySet() is unavailable if minMax() has been called","messagePattern":"arraySet\\(\\) 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":169,"sourceCode":"\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) { ; }\n        }\n        ValueRef lmin = min.get();\n        if (lmin.value >= candidate) {\n            final ValueRef cmin = new ValueRef(candidate, ref);\n            while (!min.compareAndSet(lmin, cmin) && (lmin = min.get()).value >= candidate) { ; }","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/alibaba/Sentinel/blob/a3f40ba8e900c8489bd520274739f17235a7721c/sentinel-core/src/main/java/com/alibaba/csp/sentinel/eagleeye/StatEntryFunc.java#L151-L187","documentation":"StatEntryFuncMinMax rejects arraySet(long... values) with IllegalStateException. arraySet assigns values to indexed slots of an array-strategy entry; the min/max func has no slot array — only two AtomicReference<ValueRef> fields updated via compareAndSet — so the operation cannot be honored.","triggerScenarios":"Calling arraySet(values) on a min/max entry — e.g. periodic snapshot code that overwrites slot values, pointed at a latency min/max metric by configuration error.","commonSituations":"Config mismatch between metric type and writer. Reuse of snapshot/overwrite emitters across metric kinds. Migration to min/max leaving stale arraySet call sites.","solutions":["Replace the call with minMax(candidate, ref) for min/max entries.","If slot overwrites are required, create an array-strategy entry.","Validate type/method pairing in a one-shot smoke write at startup."],"exampleFix":"// before\nfunc.arraySet(slots); // minMax func -> throws\n\n// after\nfor (int i = 0; i < slots.length; i++) { func.minMax(slots[i], \"slot\" + i); } // or use an array entry","handlingStrategy":"type-guard","validationCode":"if (func.getStatType() == 4) { func.minMax(candidate, ref); } else { func.arraySet(values); }","typeGuard":"boolean isMinMax(StatEntryFunc f) { return f.getStatType() == 4; }","tryCatchPattern":null,"preventionTips":["Snapshot/overwrite emitters must be bound only to array-strategy entries.","Check the stat type before any arraySet call in shared code.","Start each deployment with a canary write per metric."],"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"}