Skip to main content
日本語

A Red CI Run Is Not a Reason to Press Rerun

Tomohiro Iida · Published August 25, 2026 · Updated August 25, 2026

The shortest possible action after a CI run turns red is to press rerun. Some failures really do go green on a second attempt. The problem is moving forward without being able to explain why it went green. Netsujo now classifies a CI failure before rerunning it: save the first failure evidence, extract a failure signature, and assign it to deterministic, flaky, infrastructure, rate-limit, or unknown. Only then do we decide whether a rerun is allowed, whether code has to change, or whether a human has to judge.

Key takeaways

  • Classify a CI failure before rerunning it. Five classes are enough: deterministic, flaky, infrastructure, rate-limit, and unknown.
  • Save the first failure evidence before touching anything. A newer commit can cancel the older run and the original log becomes unreadable.
  • Do not read a resource-limit failure as “reverting one file fixed it”. Move both the diff and the resource setting before drawing a causal conclusion.
  • After a code change, do not reuse the previous green. Run a fresh exact-head CI.
  • Rerun only when the evidence and signature are saved, the class is flaky or rate-limit, and no code changed just before it.

Incident card

FieldValue
IncidentA CI failure was rerun without identifying the cause, and the green result alone was used to move forward.
SymptomRed and green alternated on the same pull request, and nobody could say which failure was resolved.
False assumptionIt passed on rerun, therefore the original failure was harmless.
Root causeA failure was treated as a one-off event: no evidence capture, no signature, no classification, no precondition for rerun.
Immediate fixBefore rerunning, save the job, step, exit code, and the head and tail of the log, then pick one classification and write one line of justification.
System fixFix which operations each classification allows, and require a fresh exact-head CI after any code change.
Remaining riskA wrong classification lets automation proceed on the wrong assumption.

A red run was being erased by pressing the button again

The failures we observed had completely different natures and all appeared in the same colour. On 2026-08-23, the primary rate limit on the GitHub Actions installation token stopped the workflow that verifies pull request head identity with HTTP 403. Measured that same day, the SIGNAL PR Build Evidence workflow started 100 runs in 95 minutes: 39 succeeded and 60 failed with 403. That failure had nothing to do with the content of the pull request, yet the commit status remained a failure. A different failure ended with exit 134, a heap out-of-memory in tsc that exceeded the roughly 2GB Node default; and when several Git worktrees were placed under a shared checkout, raising the Node heap to 8GB did not stop the out-of-memory condition, because complete copies of the same repository had entered the analysis scope of ESLint and TypeScript. Over the same period we also saw lint errors, type errors, and assertion failures, which reproduce every time for the same input. Treating all of these with a generic rerun makes the pipeline pass sometimes and fail other times, and only the passing attempts stay in the record.

Two false assumptions were stacked

The first is that a green rerun proves the original failure was harmless. A rerun changes the execution environment and the clock, not the code. Green only says the failure did not reproduce this time. The second is that the diff you touched last is the cause, which is especially dangerous for resource-limit failures: out-of-memory conditions and rate limits cross a threshold when input volume or call frequency changes slightly, so if reverting one file makes the run pass, the cause may be total volume rather than that file. To separate the two, move both the diff and the resource setting and compare the results. One observation in which only one variable moved is not a basis for a causal claim.

Root cause

The root cause is that a failure was treated as a one-off event. Concretely, the following were missing. Without the last of them, flaky and deterministic cannot be told apart: a first red and a fifth red look the same and mean different things.

The immediate fix

Take those three before the red run disappears, because depending on the concurrency configuration a newer commit cancels the older run and the original failure log becomes unreadable. Saying “I looked at the log” also does not let anyone decide later whether a failure was the same one, so decide the fields in advance: workflow, run id, run attempt, job, step, exit code, subject SHA, start time, runner, and the head and tail of the log. Run attempt and subject SHA are mandatory, because without those two nobody can tell afterwards whether the result varied on the same SHA or whether a different SHA produced a different failure, and the flaky judgement depends entirely on that distinction. Comparing raw logs then makes the same failure a different string every time, so drop the parts that change on every run: timestamps, run ids, temporary directory paths, elapsed time, and line numbers. What remains is the signature, and it holds three elements.

Those three joined into one line are the signature. Too fine a granularity counts one failure as several. Too coarse a granularity puts unrelated failures into one bucket. The test is whether you can choose the next operation by looking at the signature; if you cannot, it is too coarse.

Turning it into a system

ClassificationSignalAllowed next action
deterministicLint error, type error, assertion failureRerun forbidden. Change the code, then run a fresh CI.
flakyThe result varies for the same SHAOne rerun allowed. Register it and open a fix task.
infrastructureRunner startup, network, exit 134Identify the cause by measurement. Do not stop at raising a limit.
rate-limitHTTP 403, HTTP 429, rate limit textBounded automatic retry only. Never fake a success.
unknownNone of the aboveDo not rerun. Escalate to a human decision.

Preconditions for an allowed rerun

The last precondition matters most. If code changed, this is not a rerun but a new verification. The previous green and the previous red both close as results belonging to the previous SHA. Decision contract: deterministic forbids rerun; a code change requires a fresh exact-head CI and makes the previous green stale; unknown escalates to a human.

Path-aware CI branching, what to do about a check that was never executed, and how the classifier itself is kept out of the hands of the change being classified are covered by the episode on CI execution branching. How a green deploy is separated from a confirmation that production behaves as expected is covered by the episode on production verification. Both are linked at the end of this article.

A reusable checklist

Evidence

StatementClassBasis
On 2026-08-23 the Actions installation rate limit stopped head identity verification with 403, and the check moved to the Git protocol.OBSERVEDRepository workflow for pull request exact-head identity
On the same day, 100 runs started in 95 minutes with 39 successes and 60 failures at 403.OBSERVEDRepository script scripts/ci/gh-api-retry.sh
Only rate-limit errors are retried, at 5, 10, 20, and 30 seconds.IMPLEMENTEDRepository script scripts/ci/gh-api-retry.sh
Typecheck exceeds the default heap and exits 134, so 4096MB is specified.IMPLEMENTEDRepository CI workflow and package.json
A regression test detects removal of the heap setting.IMPLEMENTEDRepository test under scripts/agent-os/__tests__
Raising the heap to 8GB did not stop the out-of-memory condition; duplicated worktrees in the analysis scope did.OBSERVEDRepository document docs/agent/LEARNINGS.md
Manual reruns are isolated per run id and stale heads are rejected by the first guard.IMPLEMENTEDRepository CI workflow
Retry counts and thresholds depend on the environment and the size of the repository.INFERREDDerived from the operating range of the implementations above
Fully automated signature extraction and classification.PROPOSEDToday a human selects the classification

Limits of application

Remaining risks

Conclusion

The first decision after a red CI run is not whether to press the button. It is which class the failure belongs to. Saved failure evidence, an extracted signature, one of five classifications, the operations that classification permits, and a fresh exact-head CI after any code change: together these turn a rerun from a hopeful gesture into a decided operation.

Frequently asked questions

Should rerun be banned?
No. What is banned is a rerun you cannot explain. Transient external causes such as a rate limit are handled with a bounded retry, while deterministic failures do not change on rerun.
Reverting one file made it pass. Is that file the cause?
One observation cannot decide that. Resource-limit failures depend on whether total volume crosses a threshold, so move both the diff and the resource setting before concluding.
How fine should the signature be?
Fine enough that you can choose the next operation by looking at it. Drop the variable parts such as timestamps, run ids, temporary paths, and line numbers, then fold what remains into the exit code, the word that determines the error kind, and the job and step names.
Can the previous green be reused after a code change?
No. The previous green belongs to the previous SHA. After a code change, run CI against the exact head you are about to operate on.
How should a known flaky test be handled?
One rerun may move the work forward, but the work does not stop there. Register the test and open a fix task, otherwise the same test keeps consuming one rerun at a time.

Previous: CLOSED is not MERGEDEpisode 06 checks a claimed fix through a five-layer evidence ladder.

Next: Cutting the Actions bill nearly cut the safety checksEpisode 08 covers path-aware CI branching that keeps the required checks.

Back to the full incident logThe series hub lists all twelve episodes and the order to read them in.

We design failure evidence capture, classification, rerun preconditions, and fresh CI requirements as one operating system.

Talk to Netsujo about AI development operations