Zabbix Automation Starts With a Problem Queue You Can Trust
It's Monday, 9:04 AM. Monitoring → Problems shows 312 entries. Somewhere in there are two real incidents: a replica that stopped replicating on Saturday and a disk that will fill by Thursday. They are visually identical to the 310 entries that don't matter — the flapping CPU trigger on a batch host, the switch cascade from a five-minute maintenance reboot, the "High" severity alert that has been active for 41 days because everyone agreed it's fine.
This is the queue most Zabbix installations converge on, and it's the reason Zabbix automation efforts fail before they start: you cannot automate responses to a signal you don't trust. Zabbix itself is rarely the problem — it's collecting the data and evaluating the triggers exactly as configured. The problem is that the configuration accumulated for five years and nobody ever subtracted anything.
This guide walks through the six patterns that turn a Zabbix problem queue into noise — how each one develops, one concrete way to detect it in the frontend or via trigger expressions, and what it costs the on-call rotation. This is part one of a three-part series: part two is a hands-on guide to fixing these with native Zabbix features — trigger expressions, dependencies, actions, and the Zabbix API; part three covers putting an AI agent on top of the problem queue to triage and resolve continuously.
1. Trigger sprawl and severity inflation
How it develops. Every host gets a template, every template ships dozens of triggers, and nobody prunes after linking. The official Linux agent template alone brings CPU, memory, swap, disk, inode, interface, and service triggers — multiply by 400 hosts and you're evaluating tens of thousands of triggers, most of which nobody consciously chose. Then severity inflates: a team wants their alert noticed, so it becomes "High". A year later half the queue is High or Disaster, which means severity no longer sorts anything.
Detect it. Open Monitoring → Problems, clear all filters, and group the count by severity (the severity filter checkboxes give you counts per level as you toggle them). A healthy queue is a pyramid: many Information/Warning, few High, Disaster almost never. If your distribution is top-heavy — more High than Warning — severity has stopped encoding urgency. Cross-check the raw trigger count per host under Data collection → Hosts (the Triggers column); hosts with 80+ triggers from stacked templates are sprawl candidates.
The cost. Severity is the only field on-call uses to decide "phone down or phone up." When it's inflated, every decision requires opening the event and reading history — 30 seconds each, hundreds of times a week.
2. Flapping triggers that train people to ignore pages
How it develops. A trigger built on an instantaneous check fires the moment one value crosses the line and resolves the moment one value crosses back:
last(/Linux by Zabbix agent/system.cpu.util)>90
Any bursty workload turns this into a strobe light — PROBLEM, OK, PROBLEM, OK, twelve times an hour. There's no hysteresis and no time window, so the trigger flaps with the workload. After two weeks of this, on-call has learned the only lesson flapping teaches: this alert resolves itself, ignore it. That reflex does not stay scoped to the flapping trigger. It generalizes.
Detect it. Go to Reports → Top 100 triggers, set the time range to the last 7 days, and sort by number of status changes. Anything firing more than a handful of times per day is either a real recurring problem (rare) or a flapping expression (usual). The fix is a windowed function with a separate recovery expression — trigger expression docs — which part two covers with exact syntax:
Problem: avg(/Linux by Zabbix agent/system.cpu.util,5m)>90
Recovery: avg(/Linux by Zabbix agent/system.cpu.util,5m)<80
The cost. Flapping is the single fastest way to destroy trust in a monitoring system. One flapping Disaster trigger that pages five times a night does more damage than fifty silent misconfigurations, because it converts paging from "wake up" to "swipe away."
3. The cascade nobody configured dependencies for
How it develops. A top-of-rack switch reboots for five minutes. Zabbix, correctly, reports every host behind it unreachable — forty hosts, forty "Zabbix agent is not available" problems, plus the ICMP triggers, plus every nodata trigger downstream. One root cause, ninety queue entries, and the actual switch trigger is buried on page three. Zabbix has first-class trigger dependencies to suppress exactly this — dependent problems are hidden while the parent is down — but dependencies must be configured per trigger, and in most installations they never were.
Detect it. You don't need a report; you need the memory of your last network blip. Open Monitoring → Problems, set the time filter to that window, and count the entries per root cause. More than three problems per actual failure means missing dependencies. To audit systematically, the Zabbix API exposes it directly — trigger.get with selectDependencies returns an empty array for every trigger that depends on nothing (part two has the full curl version).
The cost. Cascades are what make people mute Zabbix in Slack. The channel that posts ninety messages for one switch reboot is a channel nobody reads during a real outage.
4. Maintenance windows that never end
How it develops. Someone creates a maintenance window for a migration — "no data collection, ends Sunday." The migration slips, so the window gets extended. Then extended again, this time to a date comfortably far away, and everyone forgets. The hosts are now unmonitored in production, indefinitely, and the queue looks cleaner for it — which is exactly why nobody notices. A maintenance window with a far-future end date is functionally a delete, except it doesn't show up in any diff.
Detect it. Open Data collection → Maintenance (Configuration → Maintenance on older versions) and read two columns: State and Active till. Expired windows that were never cleaned up are clutter; active windows with end dates months out, or covering entire host groups, are the dangerous ones. Cross-reference each against a change ticket. The maintenance docs cover the "with data collection" mode that suppresses alerts while still collecting — most permanent mutes should have been that, or a targeted trigger fix, not a blackout.
The cost. This is the inverse failure of the other five: instead of noise, silence. The incident that finally hits a permanently-muted host group arrives with zero warning and no recent data to investigate with.
5. Items rotting in "Not supported"
How it develops. An item goes Not supported when Zabbix can't collect it — the key doesn't exist after an OS upgrade, a permission changed, a UserParameter script was removed, a filesystem was renamed. The item stops collecting, every trigger built on it stops evaluating, and Zabbix keeps running happily. Unlike a down host, an unsupported item raises no problem by default. It just rots, and each one is a trigger that can no longer fire.
Detect it. Go to Data collection → Hosts, click Items, and set the State filter to Not supported. Read the error column — it tells you exactly why collection fails. Do the same for unreachable checks in Administration → Queue (queue docs), where items stuck waiting longer than 10 minutes indicate collection problems. For a permanent guardrail, Zabbix monitors itself: an internal item with key zabbix[items_unsupported] plus a trigger on its growth catches rot as it happens.
The cost. Every unsupported item is a blind spot you're confident you don't have. The disk-full trigger you're relying on may be built on an item that stopped collecting in March.
6. The trigger patterns that actually carry signal
After pruning, what deserves to page? In practice a short list of patterns carries nearly all the real signal:
- Absence, not threshold:
nodata(/host/agent.ping,5m)=1— the host stopped talking. Hard to inflate, hard to flap. - Trend, not snapshot: forecast-based disk triggers using
timeleft()— "full in 48 hours" is actionable; "82% used" is trivia. - Service checks from outside:
net.tcp.serviceand web scenarios that test what users experience, not what a process table says. - Windowed saturation: sustained
avg()over 5–15 minutes on CPU, memory, connection pools — with recovery hysteresis.
Notice what's not on the list: instantaneous thresholds on utilization metrics, which generate most of the flaps, and duplicated per-host triggers for conditions a dependency should collapse.
The on-call math
Put numbers on a 300-entry queue. If triage takes 30 seconds per entry and the queue turns over twice a week, that's five engineer-hours weekly spent distinguishing noise from signal — before anyone fixes anything. The worse cost is probabilistic: every additional noise entry lowers the chance the two real problems get opened at all. Alert fatigue isn't a morale complaint; it's a detection-latency problem. The replica that broke Saturday gets found Monday not because Zabbix was slow but because the queue made it invisible for 36 hours.
Cleanup is genuinely doable with native features — part two walks through the exact trigger expressions, dependencies, and Zabbix API calls. The catch is that hygiene decays: every new template link, host, and "temporary" mute restarts the clock.
Keep the queue honest continuously
The audits above are point-in-time; the rot is continuous. CloudThinker connects to Zabbix read-only over the API and works the live problem queue the way a careful engineer would — separating outages from flaps from noise, flagging expired mutes and unsupported items, and proposing fixes you approve before anything changes. Try CloudThinker free — 100 premium credits, no card required — or continue with the native-tools guide.
