Describe the bug
When Bloom Gateway filtering is enabled, a pipeline label filter with a case-insensitive regex literal can return no lines even though the structured-metadata value matches.
{app="a"} | device_id=~"(?i)a66347031de50be5"
The same filter works without blooms, and these variants also work with blooms:
{app="a"} | device_id=~"a66347031de50be5" # case-sensitive literal
{app="a"} | device_id=~"(?i)a66347031de50be5.*" # extra wildcard
{app="a"} | device_id=~"(?i)a66347031de50be5$" # explicit anchor
{app="a"} | device_id=~"^(?i)a66347031de50be5" # explicit anchor
To Reproduce
- Loki with bloom creation and Bloom Gateway filtering enabled for the tenant.
- Ingest a log with structured metadata
device_id="a66347031de50be5" (lowercase). Wait until a bloom is built for that chunk.
- Query:
{app="a"} | device_id=~"(?i)a66347031de50be5"
- Observed: 0 lines.
- Repeat with
| device_id=~"a66347031de50be5" or | device_id=~"(?i)a66347031de50be5.*". Those return the line.
Without blooms, pkg/logql / logqltest already treats (?i)a66347031de50be5 as an equality match (with case folding) and returns both a66347031de50be5 and A66347031DE50BE5.
Expected behavior
| device_id=~"(?i)a66347031de50be5" should return every line whose device_id value equals that hex string, ignoring case. Bloom filtering should not drop a chunk that contains a case-folded match.
Cause
ExtractTestableLabelMatchers in pkg/storage/bloom/v1/ast_extractor.go simplifies (?i)a66347031de50be5 to a KeyValueMatcher whose Value is the regex engine's canonical literal:
case regexsyn.OpLiteral:
return KeyValueMatcher{
Key: key,
Value: string(reg.Rune),
}
regexp/syntax with FoldCase stores that literal in uppercase (A66347031DE50BE5). Blooms are built from the stored metadata as-is (a66347031de50be5), so the bloom test misses and the gateway prunes the chunk.
Patterns that do not simplify to a bare OpLiteral (.*, ^, $, character classes) become UnsupportedLabelMatcher, for which bloom tests always pass. That is why adding a wildcard or anchor "fixes" the query.
Confirmed with:
{app="a"} | device_id=~"a66347031de50be5" → KeyValueMatcher{Key:"device_id", Value:"a66347031de50be5"}
{app="a"} | device_id=~"(?i)a66347031de50be5" → KeyValueMatcher{Key:"device_id", Value:"A66347031DE50BE5"}
{app="a"} | device_id=~"(?i)a66347031de50be5.*" → UnsupportedLabelMatcher{}
{app="a"} | device_id=~"(?i)a66347031de50be5$" → UnsupportedLabelMatcher{}
{app="a"} | device_id=~"^(?i)a66347031de50be5" → UnsupportedLabelMatcher{}
Workaround
Disable bloom_gateway_enable_filtering for the tenant, or rewrite the filter so the extractor cannot turn it into a case-folded equality ((?i)….*, ^, $).
Describe the bug
When Bloom Gateway filtering is enabled, a pipeline label filter with a case-insensitive regex literal can return no lines even though the structured-metadata value matches.
The same filter works without blooms, and these variants also work with blooms:
To Reproduce
device_id="a66347031de50be5"(lowercase). Wait until a bloom is built for that chunk.| device_id=~"a66347031de50be5"or| device_id=~"(?i)a66347031de50be5.*". Those return the line.Without blooms,
pkg/logql/logqltestalready treats(?i)a66347031de50be5as an equality match (with case folding) and returns botha66347031de50be5andA66347031DE50BE5.Expected behavior
| device_id=~"(?i)a66347031de50be5"should return every line whosedevice_idvalue equals that hex string, ignoring case. Bloom filtering should not drop a chunk that contains a case-folded match.Cause
ExtractTestableLabelMatchersinpkg/storage/bloom/v1/ast_extractor.gosimplifies(?i)a66347031de50be5to aKeyValueMatcherwhoseValueis the regex engine's canonical literal:regexp/syntaxwithFoldCasestores that literal in uppercase (A66347031DE50BE5). Blooms are built from the stored metadata as-is (a66347031de50be5), so the bloom test misses and the gateway prunes the chunk.Patterns that do not simplify to a bare
OpLiteral(.*,^,$, character classes) becomeUnsupportedLabelMatcher, for which bloom tests always pass. That is why adding a wildcard or anchor "fixes" the query.Confirmed with:
Workaround
Disable
bloom_gateway_enable_filteringfor the tenant, or rewrite the filter so the extractor cannot turn it into a case-folded equality ((?i)….*,^,$).