Loki Error Guide: 'queries require at least one regexp or equality matcher' — Fix Empty Stream Selectors
Fix Loki's 'queries require at least one regexp or equality matcher': add a concrete label matcher to the stream selector, avoid empty-compatible matchers, and write valid LogQL.
- #loki
- #logging
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
Loki rejects a LogQL query when its stream selector does not contain at least one matcher that meaningfully narrows the set of streams. The query returns HTTP 400 with:
parse error: queries require at least one regexp or equality matcher that does not have an empty-compatible value for the label. To circumvent this error, enter more specific label matchers or add a URL parameter with a longer time range.
Every LogQL query starts with a stream selector like {app="api"}. Loki refuses selectors that could match every stream, because that would force a scan of the entire index. A matcher is “empty-compatible” if it can match a stream where the label is absent or empty — for example {app=~".*"} or {app!="x"}. Loki requires at least one non-empty-compatible matcher (an = with a real value, or a =~ regex that cannot match empty) so the query has a bounded starting set.
Symptoms
- A query fails immediately with
queries require at least one regexp or equality matcherbefore any data is scanned. - Selectors using only negative matchers (
!=,!~) or catch-all regexes (=~".*",=~".+"on an absent label) are rejected. - Grafana Explore shows the 400 the moment you run the query, not after a delay.
- Dashboards built with variable-driven selectors break when a variable resolves to a catch-all.
- Removing the last concrete
=matcher reliably triggers the error.
Common Root Causes
- Only negative matchers — e.g.
{namespace!="kube-system"}with no positive matcher. - Catch-all regex —
{job=~".*"}matches everything, including empty, so it is empty-compatible. - Template variable resolving to
.*— a Grafana$servicevariable set to “All” expands to a catch-all. - Empty selector —
{}with only a line filter, e.g.{} |= "error". - Regex that permits empty —
=~".*"versus a bounded=~".+"on a label that is always present.
Diagnostic Workflow
Reproduce and read the parse error verbatim with logcli:
logcli query '{namespace!="kube-system"} |= "error"' --since=1h
# parse error: queries require at least one regexp or equality matcher...
Rewrite the selector to include a concrete matcher. Compare rejected versus accepted forms:
# REJECTED — only negative / catch-all matchers
{namespace!="kube-system"}
{job=~".*"}
{} |= "timeout"
# ACCEPTED — at least one non-empty-compatible matcher
{namespace="payments"}
{namespace="payments", pod!="canary"}
{job=~"api|web"} |= "timeout"
For dashboards, guard the template variable so “All” produces a real regex, not a catch-all:
# Grafana variable regex: match one-or-more real values, never empty
{service=~"$service"} # with $service = api|web|worker, valid
# Avoid $service resolving to ".*"; set the "All" value to a real regex
Confirm the label actually exists and has values before selecting on it:
logcli labels # list label names
logcli labels service # list values to pick a concrete matcher
Example Root Cause Analysis
An on-call engineer wanted “all error logs except from kube-system” and wrote {namespace!="kube-system"} |= "error". Loki returned queries require at least one regexp or equality matcher because the only matcher was negative — it is empty-compatible (it would match streams that have no namespace label at all), so Loki had no bounded starting set and refused to scan the whole index.
The fix was to anchor the selector with a positive matcher. Their real intent was application namespaces, which all shared the label tier="app". Rewriting to {tier="app", namespace!="kube-system"} |= "error" gave Loki a concrete = matcher to start from, then applied the negative filter within that bounded set. The query ran instantly. They updated the shared dashboard’s namespace variable so its “All” option expanded to a real regex like payments|checkout|web instead of .*, preventing the same error for other users.
Prevention Best Practices
- Always include at least one positive
=(or bounded=~) matcher on a present, low-cardinality label such asapp,namespace, orjob. - Use negative matchers (
!=,!~) only to refine a selector that already has a concrete matcher. - Configure Grafana template-variable “All” values as real regexes (
a|b|c), never.*. - Prefer
=~".+"over=~".*"when you need a regex, since.+is not empty-compatible on a present label. - Push content filtering into line filters (
|=,|~) and parsers rather than trying to widen the stream selector. - Teach dashboard authors that the stream selector must narrow streams; line filters narrow lines.
Quick Command Reference
# Reproduce the parse error
logcli query '{job=~".*"}' --since=15m
# Discover labels and values to build a concrete matcher
logcli labels
logcli labels app
# Valid query with a positive anchor
logcli query '{app="api"} |= "error"' --since=1h
# Rule of thumb
{app="api", level!="debug"} |= "timeout" # positive anchor + refinements
Conclusion
queries require at least one regexp or equality matcher means your LogQL stream selector could match every stream, so Loki refuses to scan the whole index. Fix it by anchoring the selector with a concrete = matcher (or a bounded =~".+") on a real, present label, then add negative matchers and line filters to refine. For dashboards, ensure template variables never resolve to a bare .*, and the error disappears while queries stay fast and bounded.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.