#23892·loki

LogQL: label filter regex `=~` is not anchored for one-sided `foo.*` / `.*foo` patterns

Author: pracucciCreated Aug 10, 2026Updated Sep 15, 2026
Labelstype/bugarea/logql

Describe the bug

A pipeline label filter regex (| name=~"…") should match the whole label value, exactly like a stream selector matcher. For a one-sided pattern — foo.* or .*foo — it matches a substring instead.

  • Affected: foo.*, .*foo, and their (?i) forms, for both =~ and !~, on parsed fields, stream labels and structured metadata.
  • Not affected: foo, foo|bar, .*foo.* (a substring match is equivalent there), pre.*ha, al[a-z]*.

To Reproduce

  1. Loki main (5bc7440e34).
  2. Two streams: {app="a", name="alpha"} and {app="a", name="prealpha"}.
  3. Run the same regex as a selector matcher and as a label filter:
logql
{app="a", name=~"al.*"}     # → name="alpha"                    (correct)
{app="a"} | name=~"al.*"    # → name="alpha", name="prealpha"   (wrong)

Expected behavior

Both queries return only name="alpha". docs/sources/query/log_queries/_index.md states that the string label filter type "work[s] exactly like Prometheus label matchers use in log stream selector", and those are fully anchored.

Cause

parseRegexpFilter(re, match, isLabel=true) in pkg/logql/log/filter.go anchors with ^(?:…)$ only on the fallback path, when regex simplification fails. Every simplified branch therefore has to anchor itself, which is what the isLabel flag is for. Simplify passes isLabel to its OpLiteral and OpAlternate branches, but the OpConcat branch calls s.simplifyConcat(reg, nil) without it, and simplifyConcat always returns newContainsFilter.

The flag arrived in #8659, which threaded it through every other branch and the anchoring fallback.

Environment:

  • Infrastructure: reproduced by a pkg/logql test on main, no deployment needed.