{"record":{"id":"e39b1f2fe0571598","repo":"elastic/elasticsearch","slug":"caught-a-stackoverflowerror-while-processing-gsub","errorCode":null,"errorMessage":"Caught a StackOverflowError while processing gsub pattern: [{}]","messagePattern":"Caught a StackOverflowError while processing gsub pattern: \\[(.+?)\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/GsubProcessor.java","lineNumber":68,"sourceCode":"\n    String getReplacement() {\n        return replacement;\n    }\n\n    @Override\n    protected String process(String value) {\n        try {\n            return pattern.matcher(value).replaceAll(replacement);\n        } catch (StackOverflowError e) {\n            /*\n             * A bad regex on problematic data can trigger a StackOverflowError. In this case we can safely recover from the\n             * StackOverflowError, so we rethrow it as an Exception instead. This way the document fails this processor, but processing\n             * can carry on. The value would be useful to log here, but we do not do so for because we do not want to write potentially\n             * sensitive data to the logs.\n             */\n            String message = \"Caught a StackOverflowError while processing gsub pattern: [\" + pattern + \"]\";\n            logger.trace(message, e);\n            throw new IllegalArgumentException(message);\n        }\n    }\n\n    @Override\n    public String getType() {\n        return TYPE;\n    }\n\n    public static final class Factory extends AbstractStringProcessor.Factory {\n\n        public Factory() {\n            super(TYPE);\n        }\n\n        @Override\n        protected GsubProcessor newProcessor(\n            String processorTag,\n            String description,","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/GsubProcessor.java#L50-L86","documentation":"Thrown by GsubProcessor.process when java.util.regex's replaceAll triggers a StackOverflowError on pathological regex/data combinations. The processor catches the SOE (a recoverable JVM error) and rethrows as IllegalArgumentException so the document fails this processor but ingest continues. The offending pattern is logged at TRACE; the value is deliberately not logged to avoid leaking sensitive data.","triggerScenarios":"A gsub processor with a regex prone to catastrophic backtracking (e.g. nested quantifiers) running on a long or adversarial input string. JVM stack depth exceeded during NFA evaluation.","commonSituations":"User-supplied regex patterns not anchored/optimized, large unstructured text fields, pattern intended for short strings applied to whole documents, or upgrade of JDK changing regex engine behavior.","solutions":["Rewrite the regex to avoid catastrophic backtracking (avoid nested quantifiers like (a+)+, anchor patterns, use possessive quantifiers).","Increase JVM thread stack size (-Xss) as a stopgap for borderline inputs.","Pre-truncate or sanitize overly long input strings before applying gsub.","Test the regex in isolation against representative data before deploying."],"exampleFix":"// before\n{\"gsub\": {\"field\": \"msg\", \"pattern\": \"(a+)+b\", \"replacement\": \"x\"}}\n// after\n{\"gsub\": {\"field\": \"msg\", \"pattern\": \"a+b\", \"replacement\": \"x\"}}","handlingStrategy":"try-catch","validationCode":"// Pre-validate regex by testing on representative inputs with bounded length\ntry {\n    Pattern.compile(regex).matcher(sample).replaceAll(replacement);\n} catch (StackOverflowError soe) {\n    // pattern is dangerous — reject at pipeline-create time\n}","typeGuard":null,"tryCatchPattern":"try {\n    gsubProcessor.execute(doc);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"StackOverflowError while processing gsub pattern\")) {\n        // route to failure store; flag the pattern for review\n    } else throw e;\n}","preventionTips":["Avoid catastrophic-backtracking patterns (nested quantifiers like (a+)+).","Test user-supplied regex against worst-case long inputs before deployment.","Increase -Xss for the ingest JVM if patterns are borderline.","Pre-truncate long input strings before gsub."],"tags":["ingest","gsub","regex","stackoverflow","jvm"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}