[Breaking Change] Regex Engine Update for Config

CircleCI will update the regex engine used for when: matches: pattern: conditions on June 28, 2026. After this date, configs using certain advanced regex features in pattern: fields will fail to compile. This post explains what’s changing, how to check if you’re affected, and how to rewrite affected patterns.

Background

The when: matches: condition lets you control whether a job or step runs based on whether a value (like a branch name or tag) matches a regex pattern. We are moving to a new regex engine which is more reliable, but does not support a small number of advanced regex features that the current engine accepts.

Am I affected?

Search your .circleci/config.yml (and any orb source that feeds into your config) for when: matches: pattern: fields. If any pattern: value contains the following, you’ll need to rewrite it:

Negative lookaheads (`(?!...)`)

Negative lookaheads assert that the string does not match a pattern at the current position. They’re typically used to run a job on every branch except a specific set.

Before (will break):

when:
  matches:
    pattern: "^(?!main).*$"
    value: << pipeline.git.branch >>

This matches any branch except main.

Fix:

branches:
  ignore:
    - main

Before (will break):

when:
  matches:
    pattern: "^(?!master|staging|release|hotfix).*$"
    value: << pipeline.git.branch >>

Fix: Replace with CircleCI’s native branches: ignore: list or pipeline filter expressions (preferred, as expressions don’t couple your config to a specific VCS provider):

branches:
  ignore:
    - master
    - /^staging.*/
    - /^release.*/
    - /^hotfix.*/

Here’s a more complex example with multiple exclusions:

Before (will break):

^(?!develop$)(?!build_all$)(?!integration-....?)(?!integration2)(?!fedint-us1$)(?!hotfix/.*?/.*$).*

Fix:

branches:
  ignore:
    - develop
    - build_all
    - /^integration-.{4,5}/
    - /^integration2/
    - fedint-us1
    - /^hotfix\/.+\/.+/
Negative lookbehinds (`(?<!...)`)

Negative lookbehinds assert that the string does not have a particular substring immediately before the current position. There’s no single-regex equivalent, but you can split the logic into a positive match and a negative exclusion.

Before (will break):

when:
  matches:
    pattern: "^@myorg\\/[\\w-]+(?<!-uat)@\\d+\\.\\d+\\.\\d+-rc\\.\\d+$"
    value: << pipeline.git.tag >>

This matches package version strings like @myorg/some-pkg@1.2.3-rc.4 but excludes packages ending in -uat.

Fix: Split into and + not:

when:
  and:
    - matches:
        pattern: "^@myorg\\/[\\w-]+@\\d+\\.\\d+\\.\\d+-rc\\.\\d+$"
        value: << pipeline.git.tag >>
    - not:
        matches:
          pattern: "-uat@"
          value: << pipeline.git.tag >>

Or in pipeline logic, split into an only and an ignore rule that together cover the same space without a lookbehind.

Possessive quantifiers (`?+`, `*+`, `++`)

Possessive quantifiers match greedily and never backtrack. Simply remove the trailing + to use a plain quantifier. Behavior is identical for all practical inputs.

Before (will break):

when:
  matches:
    pattern: "^staging[0-9]?+$"
    value: << pipeline.git.branch >>

Fix: Remove the trailing +:

when:
  matches:
    pattern: "^staging[0-9]?$"
    value: << pipeline.git.branch >>
Backreferences (`\1`, `\2`, etc.)

Backreferences match the same text that was previously captured by a numbered group, letting a single pattern enforce that two substrings are identical. The new engine cannot do this in a single pattern.

Before (will break):

^release/(v\d+\.\d+\.\d+)/\1$

This matches tags like release/v1.2.3/v1.2.3 where the version appears twice and both must be identical.

Fix — loosen the regex (recommended if tags are produced by release tooling):

when:
  matches:
    pattern: "^release/v\\d+\\.\\d+\\.\\d+/v\\d+\\.\\d+\\.\\d+$"
    value: << pipeline.git.tag >>

This no longer enforces that both version strings are identical, but in practice the tag is produced by tooling, so a mismatch is unlikely.

Alternatively, if the set of valid values is small and known, enumerate them with a when: or: block.

Coming soon: Regex validation

We are building a way for you to validate that your updated regex patterns will be supported by the new engine before the June 28 cutover. We’ll update this thread when it’s available.

Need help?

If you’re unsure whether your config is affected or need help rewriting a specific pattern, reply to this thread or open a support ticket.