Invalid Regular Expression

ID

kotlin.bad_regex_syntax

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Kotlin

Tags

reliability

Description

Reports a Regex(…​) construction, a String.toRegex() call or a Pattern.compile(…​) call whose pattern is a statically known string that is not valid regular-expression syntax.

Validity is decided by compiling the pattern with the very engine Kotlin’s Regex delegates to, so a finding is not an approximation: the pattern will throw.

Rationale

// Bad
val group = Regex("(unclosed")     // PatternSyntaxException: Unclosed group
val range = Regex("a{3,1}")        // PatternSyntaxException: Illegal repetition range
val empty = Regex("[]")            // PatternSyntaxException: Unclosed character class
  • The exception is thrown the moment the expression is evaluated, so the code path containing it is dead on arrival — it can never do the matching it was written for.

  • Nothing about the source hints at it: an invalid pattern compiles fine as Kotlin and only fails at run time, often on a rarely taken branch that no test covers.

  • Patterns are frequently copied between languages, and the grammars differ. [], [^], a lone { and a{,3} are legal in JavaScript and rejected here; conversely the possessive quantifier a++ and the unscoped inline flag group (?i) are rejected in JavaScript and perfectly valid here.

Remediation

Fix the pattern. The exception’s description names the exact problem — an unclosed group or character class, a repetition range whose bounds are in the wrong order, an unsupported escape.

// Good
val group = Regex("(closed)")
val range = Regex("a{1,3}")
val empty = Regex("[a-z]")

What is not reported

A pattern that is not statically known — built by concatenation, interpolated, held in a variable, or returned by another call — is not reported, since the string the engine will compile is not known here.

String.replace("(unclosed", "-") is not reported either: that overload takes a plain string and replaces it literally, so no regular expression is compiled. The same holds for String.split(vararg String) and String.replaceFirst(String, String), and for Regex.fromLiteral(…​), which matches its argument as plain text.

© 2026 Xygeni. All rights reserved