{"record":{"id":"74d86834c3921808","repo":"elastic/elasticsearch","slug":"can-t-use-scalefunction-as-scale-with-this","errorCode":null,"errorMessage":"Can't use ${scaleFunction} as scale with ${this}","messagePattern":"Can't use (.+?) as scale with (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/tdigest/src/main/java/org/elasticsearch/tdigest/TDigest.java","lineNumber":163,"sourceCode":"    public abstract double quantile(double q);\n\n    /**\n     * Returns the current compression factor.\n     *\n     * @return The compression factor originally used to set up the TDigest.\n     */\n    public abstract double compression();\n\n    /**\n     * Returns the number of bytes required to encode this TDigest using #asBytes().\n     *\n     * @return The number of bytes required.\n     */\n    public abstract int byteSize();\n\n    public void setScaleFunction(ScaleFunction scaleFunction) {\n        if (scaleFunction.toString().endsWith(\"NO_NORM\")) {\n            throw new IllegalArgumentException(String.format(Locale.ROOT, \"Can't use %s as scale with %s\", scaleFunction, this.getClass()));\n        }\n        this.scale = scaleFunction;\n    }\n\n    /**\n     * Add all of the centroids of another digest to this one.\n     *\n     * @param other The other digest\n     */\n    public abstract void add(TDigestReadView other);\n\n    /**\n     * Prepare internal structure for loading the requested number of samples.\n     * @param size number of samples to be loaded\n     */\n    public void reserve(long size) {}\n\n    public double getMin() {","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/tdigest/src/main/java/org/elasticsearch/tdigest/TDigest.java#L145-L181","documentation":"TDigest.setScaleFunction rejects any ScaleFunction whose toString() ends with NO_NORM. Un-normalised scale functions are mathematically incompatible with how this t-digest lays out centroids, so the configuration is rejected rather than producing silently wrong quantiles.","triggerScenarios":"Calling tdigest.setScaleFunction(fn) where fn.toString() ends in NO_NORM (e.g. k_0_NO_NORM, k_2_NO_NORM, normalAsin_NO_NORM). The check is string-based on the function name suffix.","commonSituations":"Programmatically tuning the compression profile and selecting a NO_NORM variant by mistake; copy-pasting scale configuration from a different t-digest implementation that allows un-normalised scales; serialising/deserialising a digest and re-applying the wrong scale on restore.","solutions":["Use the normalised counterpart of the scale function (the name without the NO_NORM suffix)","If you specifically need a NO_NORM scale, switch to a digest implementation that supports it instead of forcing it here","Validate the ScaleFunction name before assignment"],"exampleFix":"// before\ndigest.setScaleFunction(ScaleFunction.K_0_NO_NORM);\n// after\ndigest.setScaleFunction(ScaleFunction.K_0);","handlingStrategy":"validation","validationCode":"String name = scaleFunction.toString();\nif (name.endsWith(\"NO_NORM\")) {\n    throw new IllegalArgumentException(\"NO_NORM scales are not supported by TDigest: \" + name);\n}\ndigest.setScaleFunction(scaleFunction);","typeGuard":"static boolean isSupportedScale(ScaleFunction f) {\n    return f != null && !f.toString().endsWith(\"NO_NORM\");\n}","tryCatchPattern":"try { digest.setScaleFunction(fn); }\ncatch (IllegalArgumentException e) { /* pick the normalised variant */ }","preventionTips":["Use the normalised counterpart by default","Do not persist a NO_NORM scale alongside a TDigest","Document the chosen scale next to digest construction"],"tags":["tdigest","scale-function","config"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}