elastic/elasticsearch · error · IllegalArgumentException

Filter exceeds maximum depth at [${filter}]

Error message

Filter exceeds maximum depth at [${filter}]

What it means

Thrown by FilterPath.FilterPathBuilder.insertNode when the depth of a filter path exceeds MAX_TREE_DEPTH (500). FilterPath is used by source filtering (`_source.includes/excludes`) and `filter_path` on REST responses. The depth check is a denial-of-service guard preventing pathological, deeply-nested filter expressions from consuming excessive memory/CPU during trie construction.

Source

Thrown at libs/x-content/src/main/java/org/elasticsearch/xcontent/support/filtering/FilterPath.java:161

            BuildNode(boolean isFinalNode) {
                children = new HashMap<>();
                this.isFinalNode = isFinalNode;
            }
        }

        private final BuildNode root = new BuildNode(false);

        void insert(String filter) {
            insertNode(filter, root, 0);
        }

        FilterPath build() {
            return buildPath("", root);
        }

        static void insertNode(String filter, BuildNode node, int depth) {
            if (depth > MAX_TREE_DEPTH) {
                throw new IllegalArgumentException(
                    "Filter exceeds maximum depth at [" + (filter.length() > 100 ? filter.substring(0, 100) : filter) + "]"
                );
            }
            int end = filter.length();
            int splitPosition = -1;
            boolean findEscapes = false;
            for (int i = 0; i < end; i++) {
                char c = filter.charAt(i);
                if (c == '.') {
                    splitPosition = i;
                    break;
                } else if ((c == '\\') && (i + 1 < end) && (filter.charAt(i + 1) == '.')) {
                    ++i;
                    findEscapes = true;
                }
            }

            if (splitPosition > 0) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Reduce the filter path to fewer than 500 segments; prefer wildcard patterns (`a.*.b`) over fully enumerated deep paths.
  2. Audit the code that builds the filter string for runaway concatenation loops.
  3. If you genuinely need such depth, redesign the document model to flatten nesting or use a different filtering strategy.
  4. Validate the filter string length/segment count client-side before sending the request.

Example fix

// before: filter_path built by unbounded loop
String path = ""; for (int i=0;i<1000;i++){ path += "a."; }
// after: cap the depth client-side
if (path.split("\\.").length > 500) throw new IllegalArgumentException("filter too deep");
Defensive patterns

Strategy: validation

Validate before calling

static void checkFilterDepth(String filter) {
  if (filter.split("\\.").length > 500) {
    throw new IllegalArgumentException("filter path too deep (>500 segments): " + filter);
  }
}

Prevention

When it happens

Trigger: Submitting a `_source` include/exclude pattern or a REST `filter_path` query parameter with more than 500 dot-separated segments (e.g. a.a.a... 501 levels deep), or an expression that the splitting logic recurses on past depth 500. Generated/programmatic filter strings can hit this when a loop concatenates path segments unbounded.

Common situations: Automated clients building filter paths from arbitrarily deep object schemas. Misconfigured tools that concatenate filter segments without bounds. A payload generator bug repeating a segment thousands of times. Trying to filter on a deeply nested document model where the path is constructed dynamically.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/72902ec8dd5d3e05. Report an issue: GitHub.