Renovate Opened 40 MRs, 6 Are Red: Now What?

The green Renovate MRs were never the problem. Patch bump, pipeline green, automerge, done: that part runs itself. The actual work starts with the handful that come back red, because every one of those means a dependency changed something your code depends on, and no bot setting will merge it for you.

This is the triage workflow I use when the red ones pile up, plus the Renovate config that keeps the pile small.

Why red MRs accumulate

A red Renovate MR is one of four things, in descending order of frequency:

  1. Flaky CI. The update is fine, your pipeline is not.
  2. Stricter defaults. The dependency works, but its new version enables checks your existing code fails. Linters and type checkers love doing this on major bumps.
  3. Real breaking change. Renamed API, dropped runtime support, changed behavior.
  4. Peer dependency conflicts. The bump is valid in isolation and impossible in your tree.

The reason they accumulate is that none of these can be resolved by looking at the MR itself. You have to open the failed job, read the log, and often open the dependency's changelog too. That is a context switch nobody volunteers for, so the MRs sit, the branches go stale, and Renovate keeps rebasing them against a moving main.

Step 1: Separate flaky from real

Cheapest filter first: retry the failed job once.

# GitLab CLI, from the MR's pipeline
glab ci retry --pipeline-id <id>

If it goes green, it was your CI, not the update. If you retry the same jobs every week, fix that before touching any dependency policy: flaky pipelines poison every automated workflow you build on top of them.

Step 2: Read the log bottom-up

Failed job logs answer faster when read from the end. The last 30 lines almost always contain the actual error; everything above is setup noise.

# last lines of the failing job, no browser needed
glab ci trace <job-id> | tail -30

What you are classifying: is the failure in the dependency (import fails, API missing) or in your code (new rule, stricter type, deprecated call you still use)? These have opposite fixes. The first means read the migration guide. The second means your code needs a small change, and the update itself is harmless.

A real example from a repo I looked at recently: an eslint config package got a major bump and the pipeline went red. The log showed three lint errors in existing test files, all from two newly enabled rules. The fix was three lines in the tests, nothing in the dependency. Total change:

- expectedUrl: `${urlPrefix}`
+ expectedUrl: urlPrefix

- url: 'http://example.com'
+ url: 'https://example.com'

That MR had been red for days. The fix took minutes once someone actually read the log. Most red Renovate MRs look exactly like this: small, mechanical, and blocked purely on a human context switch.

Step 3: Fix forward on the Renovate branch

When the fix belongs in your code, commit it directly onto Renovate's branch instead of closing the MR and doing the bump by hand later:

git fetch origin renovate/eslint-config-9.x
git checkout renovate/eslint-config-9.x
# make the fix, then
git commit -am "fix lint errors from new unicorn rules"
git push origin renovate/eslint-config-9.x

One gotcha: by default Renovate force-pushes its branches when it rebases, which eats your commit. Tell it to leave updated branches alone:

{
  "rebaseWhen": "conflicted"
}

With rebaseWhen: "conflicted" Renovate only rebases when the branch actually conflicts with main, so a fix commit on top of its branch survives. Alternatively, ticking the "stop updates" checkbox in the MR description does the same for a single MR.

Step 4: Make the config carry the routine

The goal of the config is that green MRs never need a human and red MRs are labeled, grouped, and few:

{
  "extends": ["config:recommended"],
  "packageRules": [
    {
      "matchUpdateTypes": ["patch", "minor"],
      "matchCurrentVersion": "!/^0/",
      "automerge": true
    },
    {
      "matchUpdateTypes": ["major"],
      "dependencyDashboardApproval": true,
      "addLabels": ["deps-major"]
    }
  ],
  "prConcurrentLimit": 5,
  "rebaseWhen": "conflicted"
}
  • Automerge patch and minor for stable packages. If your test suite cannot be trusted to gate a patch bump, that is a test problem, not a Renovate problem.
  • Majors wait for approval on the dependency dashboard. They land when you have capacity, not 40 at once on Monday morning.
  • Concurrency limit keeps the open-MR count reviewable. An MR wall nobody reads is worse than a slower update cadence.

The part that stays manual

After all of this, the residue is constant: a few MRs a week where someone reads a log, understands a change, and writes a small fix. The work is mechanical, but it needs the context sitting in the job trace and a human call on what the right fix is, which is exactly why it resists full automation. The green MRs never needed you. These few do, and budgeting for them is the honest cost of automated updates.

Takeaways

  • Retry once before investigating: flaky CI is the most common "broken" update.
  • Read job logs from the bottom; classify the failure as dependency-side or your-side before opening any changelog.
  • Commit fixes onto the Renovate branch with rebaseWhen: "conflicted" set, so the bot does not force-push over you.
  • Automerge green patch/minor updates, gate majors behind the dependency dashboard, cap concurrent MRs.
  • Budget for the residue: a handful of small, mechanical fixes per week is the real cost of automated updates.
·share on