{"record":{"id":"2beb64d83692aa56","repo":"elastic/elasticsearch","slug":"valuessource-array-index-ordinal-out-of-bounds","errorCode":null,"errorMessage":"ValuesSource array index {ordinal} out of bounds","messagePattern":"ValuesSource array index (.+?) out of bounds","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"modules/aggregations/src/main/java/org/elasticsearch/aggregations/metric/ArrayValuesSource.java","lineNumber":39,"sourceCode":" */\npublic abstract class ArrayValuesSource<VS extends ValuesSource> {\n    protected final MultiValueMode multiValueMode;\n    protected String[] names;\n    protected VS[] values;\n\n    public static class NumericArrayValuesSource extends ArrayValuesSource<ValuesSource.Numeric> {\n        public NumericArrayValuesSource(Map<String, ValuesSource.Numeric> valuesSources, MultiValueMode multiValueMode) {\n            super(valuesSources, multiValueMode);\n            if (valuesSources != null) {\n                this.values = valuesSources.values().toArray(new ValuesSource.Numeric[0]);\n            } else {\n                this.values = new ValuesSource.Numeric[0];\n            }\n        }\n\n        public DoubleValues getField(final int ordinal, LeafReaderContext ctx) throws IOException {\n            if (ordinal > names.length) {\n                throw new IndexOutOfBoundsException(\"ValuesSource array index \" + ordinal + \" out of bounds\");\n            }\n            return multiValueMode.select(values[ordinal].doubleValues(ctx));\n        }\n    }\n\n    public static class BytesArrayValuesSource extends ArrayValuesSource<ValuesSource.Bytes> {\n        public BytesArrayValuesSource(Map<String, ValuesSource.Bytes> valuesSources, MultiValueMode multiValueMode) {\n            super(valuesSources, multiValueMode);\n            this.values = valuesSources.values().toArray(new ValuesSource.Bytes[0]);\n        }\n\n        public Object getField(final int ordinal, LeafReaderContext ctx) throws IOException {\n            return values[ordinal].bytesValues(ctx);\n        }\n    }\n\n    public static class GeoPointValuesSource extends ArrayValuesSource<ValuesSource.GeoPoint> {\n        public GeoPointValuesSource(Map<String, ValuesSource.GeoPoint> valuesSources, MultiValueMode multiValueMode) {","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/aggregations/src/main/java/org/elasticsearch/aggregations/metric/ArrayValuesSource.java#L21-L57","documentation":"Thrown by NumericArrayValuesSource.getField when the requested `ordinal` exceeds the bounds of the values array. NOTE: the guard `ordinal > names.length` is an off-by-one bug — it should be `>=` — so the explicit message is only emitted for ordinals strictly greater than the length; an ordinal exactly equal to names.length passes the guard and throws a raw ArrayIndexOutOfBoundsException from values[ordinal] on the next line. This indicates a mismatch between the number of fields configured on the array aggregation and the ordinal requested by the aggregator.","triggerScenarios":"An internal mismatch where a multi-field metric aggregation (e.g. matrix_stats, percentile ranks over multiple fields, or a custom array-source aggregator) requests a field ordinal that was not registered. Reached when the valuesSources map provided to NumericArrayValuesSource has fewer entries than the ordinal index passed to getField.","commonSituations":"Custom plugins implementing ArrayValuesSource-backed aggregations with inconsistent field/ordinal bookkeeping. Bugs in aggregation wiring after a refactor that changed the field set. Edge cases where a field is omitted from configuration but the aggregator still asks for it.","solutions":["Ensure the valuesSources map passed to the ArrayValuesSource contains every field the aggregator will request by ordinal.","In custom aggregations, keep the ordinal-to-field mapping in sync with the registered fields.","If you are an end user (not a plugin author), report this with the aggregation config — it usually indicates a bug in the aggregation implementation.","Validate field counts in your aggregator's build step before reading leaves."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (ordinal < 0 || ordinal >= values.length) {\n  throw new IndexOutOfBoundsException(\"ordinal \" + ordinal + \" not in [0,\" + values.length + \")\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep ordinal-to-field mappings in sync with the valuesSources map.","Validate field counts in custom aggregations' build step.","Report unexpected occurrences — the in-source guard has an off-by-one (uses > instead of >=)."],"tags":["aggregations","array-values-source","internal","off-by-one","bounds"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}