{"record":{"id":"65d8d92f39af60f1","repo":"elastic/elasticsearch","slug":"circular-reference-in-pattern-back","errorCode":null,"errorMessage":"circular reference in pattern back [{}]","messagePattern":"circular reference in pattern back \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/grok/src/main/java/org/elasticsearch/grok/Grok.java","lineNumber":151,"sourceCode":"            }\n            handleInterrupted(result);\n            if (result < 0) {\n                return res.append(grokPattern).toString();\n            }\n\n            Region region = matcher.getEagerRegion();\n            String namedPatternRef = groupMatch(NAME_GROUP, region, grokPattern);\n            String subName = groupMatch(SUBNAME_GROUP, region, grokPattern);\n            // TODO(tal): Support definitions\n            @SuppressWarnings(\"unused\")\n            String definition = groupMatch(DEFINITION_GROUP, region, grokPattern);\n            String patternName = groupMatch(PATTERN_GROUP, region, grokPattern);\n            String pattern = patternBank.get(patternName);\n            if (pattern == null) {\n                throw new IllegalArgumentException(\"Unable to find pattern [\" + patternName + \"] in Grok's pattern dictionary\");\n            }\n            if (pattern.contains(\"%{\" + patternName + \"}\") || pattern.contains(\"%{\" + patternName + \":\")) {\n                throw new IllegalArgumentException(\"circular reference in pattern back [\" + patternName + \"]\");\n            }\n            String grokPart;\n            if (namedCaptures && subName != null) {\n                grokPart = String.format(Locale.US, \"(?<%s>%s)\", namedPatternRef, pattern);\n            } else if (namedCaptures) {\n                grokPart = String.format(Locale.US, \"(?:%s)\", pattern);\n            } else {\n                grokPart = String.format(Locale.US, \"(?<%s>%s)\", patternName + \"_\" + result, pattern);\n            }\n            String start = new String(grokPatternBytes, 0, result, StandardCharsets.UTF_8);\n            String rest = new String(\n                grokPatternBytes,\n                region.getEnd(0),\n                grokPatternBytes.length - region.getEnd(0),\n                StandardCharsets.UTF_8\n            );\n            grokPattern = grokPart + rest;\n            res.append(start);","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/grok/src/main/java/org/elasticsearch/grok/Grok.java#L133-L169","documentation":"Thrown by Grok.toRegex() when a resolved pattern definition contains a self-reference — i.e., the pattern named PATTERN_NAME, when looked up from the bank, contains the text %{PATTERN_NAME} or %{PATTERN_NAME:. This would cause infinite recursion during pattern expansion, so it is detected and rejected.","triggerScenarios":"Defining a pattern in the PatternBank where the pattern's value references itself. For example, registering pattern 'FOO' with value '%{FOO} bar' or '%{FOO:subname} bar'. The toRegex() method detects this when it resolves %{FOO} and finds that the expansion of FOO contains another %{FOO} reference.","commonSituations":"User-defined grok pattern with a typo creating a circular reference; copy-paste error when defining custom patterns in the grok ingest processor; importing patterns from another source that has circular definitions.","solutions":["Fix the circular reference in the pattern definition — a pattern must not reference itself directly.","If indirect circular references (A references B references A) exist, the MAX_TO_REGEX_ITERATIONS limit (error 616) will catch them instead; break the cycle by renaming or restructuring.","Validate custom patterns before registering them in the PatternBank."],"exampleFix":"// before — circular reference\n// pattern file: FOO %{FOO} extra\n\n// after — no self-reference\n// pattern file: FOO \\d+ extra","handlingStrategy":"validation","validationCode":"// Check for direct self-references before registering a pattern\nfor (Map.Entry<String, String> entry : customPatterns.entrySet()) {\n    String name = entry.getKey();\n    String def = entry.getValue();\n    if (def.contains(\"%{\" + name + \"}\") || def.contains(\"%{\" + name + \":\")) {\n        throw new IllegalArgumentException(\"Pattern '\" + name + \"' contains a circular self-reference\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    new Grok(bank, pattern, callback);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"circular reference\")) {\n        // fix the pattern definition that references itself\n    }\n    throw e;\n}","preventionTips":["Never define a pattern that directly references itself.","Review custom pattern definitions for self-references before loading them.","Use unique names for patterns to avoid accidental name collisions that create cycles."],"tags":["grok","pattern-matching","validation","circular-reference","ingest"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}