New AnnouncementOpenSRE’s SRE Agent is now Open Source

Build failure taxonomy: what actually breaks main

A practical taxonomy of CI/CD failure modes, from flakes and infra drift to real regressions, and how teams should route each one.

const metadata = ; Most teams treat every red build the same way: open logs, ask who touched it last, maybe re-run. That works until volume scales. At hundreds of merges per week, how a build failed matters as much as that it failed. We reviewed failure patterns across trunk-based teams running merge queues and blocking CI gates. The same six categories showed up repeatedly. The six failure modes | Category | Share of red builds* | Typical signal | First response | | | | | | | Code regression | 35–45% | Fails on first run, stable on revert | Assign to author / codeowner | | Test flake | 15–25% | Passes on re-run, no code change | Quarantine test, don't block queue | | Infrastructure | 10–18% | Runner, registry, or cache errors | Route to platform, fail fast | | Dependency drift | 8–14% | Lockfile, base image, or transitive bump | Pin, bisect, or rollback dep | | Environment mismatch | 5–10% | Passes locally, fails in CI | Reproduce container config | | Configuration | 3–8% | Feature flag, env var, or pipeline YAML | Diff config, not code | \*Ranges from aggregated patterns across mid-size engineering orgs; your distribution will vary. Why taxonomy beats triage-by-Slack Without categories, every failure becomes a human investigation. Engineers context-switch into logs before knowing whether the problem is theirs, platform's, or a bad test. Teams that tag failures at detection time report: - 40% faster first meaningful action (re-run vs fix vs escalate) - Lower re-run rate: flakes stop getting "fixed" with empty commits - Clearer platform backlog: infra failures surface as trends, not one-offs Code regression vs flake: the hard boundary The costliest mistake is quarantining a real bug or blocking main on a flaky suite. Use this decision tree at failure time: 1. Did the same commit fail twice on different runners? → Likely real 2. Did a re-run without changes pass? → Likely flake 3. Did failure start after a dependency or base image change? → Dependency drift 4. Did multiple unrelated PRs fail the same step simultaneously? → Infrastructure Automating this classification, even heuristically, is where CI agents earn their keep. Infrastructure failures hide in plain sight Registry auth timeouts, exhausted disk on self-hosted runners, and stale build caches often look like test failures. The giveaway is correlation: unrelated changes failing the same step within minutes. Platform teams that run preflight checks before expensive suites cut infra-driven queue failures by more than half in the merge-queue case studies we've seen. What to instrument To populate this taxonomy automatically, capture at failure time: - Step and job identity: not just "tests failed" - Runner type and region - Re-run outcome on unchanged commit - Diff scope: code, lockfile, Dockerfile, workflow file - Historical flake score per test Structured failure context turns a red badge into a routed ticket. Implication Reliability improvements compound when failures are classified before humans engage. The goal isn't perfect diagnosis on the first attempt, it's sending each failure down the right path in under a minute. That's the difference between a merge queue that clears and one that trains engineers to ignore red.