Pipetrics

GitHub Actions Negative Durations After Reruns

GitHub Actions negative durations can appear when rerun jobs contain reversed timestamps. Learn why they happen and how Pipetrics keeps CI metrics accurate.

GitHub Actions negative durations should be impossible. Still, we found them in a Pipetrics repository summary after a workflow rerun.

The problem came from timestamps sent by GitHub for skipped jobs. The example values differ from production data, but they preserve the behavior we observed.

This was not a cosmetic chart issue. Invalid negative intervals flowed into a monthly repository total, offset valid runtime, and could therefore distort performance and modeled cost analysis.

GitHub reruns can return stale completion timestamps

When GitHub reran a workflow, it recreated skipped jobs with new created_at and started_at values. Their completed_at value, however, still referred to the earlier attempt.

A simplified example looks like this:

created_at:   2026-07-24T09:14:00Z
started_at:   2026-07-24T09:14:00Z
completed_at: 2026-07-23T21:09:00Z

In this example, the job appears to finish 12 hours and 5 minutes before it starts.

We confirmed the reversed timestamps in the original event payload. Our webhook processing, storage, and date parsing preserved the values correctly. The data received from GitHub already contained the inconsistency.

GitHub documents how users can rerun workflows and jobs, but an analytics system should not assume that every timestamp combination returned for a recreated skipped job is valid.

The validation invariant

For any job interval used in runtime analysis, Pipetrics now requires:

started_at is present
completed_at is present
completed_at >= started_at
conclusion is not skipped

The exact storage layer may preserve the original timestamps for diagnosis, but aggregations must not treat an invalid interval as elapsed time. Clamping a negative value to zero would hide the upstream inconsistency; rejecting it keeps the eligibility rule explicit.

Why Pipetrics displayed a negative runtime

Pipetrics calculated job duration by subtracting started_at from completed_at. That works for normal jobs, but a stale completion timestamp produces a negative result.

Our monthly total then included several affected skipped jobs. Their negative durations offset valid workflow runtime, which caused the impossible number shown in the repository overview.

The same duration could feed several downstream views. We therefore traced every aggregation that used job runtime rather than patching only the repository summary:

  • Repository and workflow runtime totals
  • Average, median, and p95 job duration
  • Failed runtime
  • Cost and billing estimates derived from runner time
  • Rerun and attempt analysis

One shared eligibility rule prevents those views from disagreeing about which jobs count.

How we fixed GitHub Actions negative durations

Pipetrics now excludes skipped jobs and rejects any job whose completion time is earlier than its start time. We still include valid jobs from every rerun attempt in runtime and cost calculations.

We shipped the fix in August 2026. Repository summaries now reflect valid GitHub Actions runtime without allowing reversed timestamps to distort the result.

Why valid rerun attempts still count

A rerun consumes real runner capacity and developer time. Keeping only the final attempt would understate total usage, failed work, and the time required to reach a successful result. Pipetrics therefore includes each valid attempt while applying the same timestamp and conclusion rules to every job.

This distinction matters for both GitHub Actions performance monitoring and GitHub Actions cost monitoring. Reliable optimization depends on counting work that actually ran without allowing malformed intervals to cancel it out.

Safeguards for CI analytics systems

If you process GitHub Actions job timestamps, add checks at several boundaries:

  1. Preserve the raw payload or enough diagnostic context to verify upstream behavior.
  2. Validate timestamp ordering before calculating a duration.
  3. Define whether skipped, cancelled, and incomplete jobs are eligible for each metric.
  4. Apply one shared rule across summaries, percentiles, costs, and billing estimates.
  5. Alert on rejected intervals so a new API edge case does not disappear silently.
  6. Test reruns with successful, failed, cancelled, and skipped jobs.

The broader lesson is simple: timestamps from an external API are data, not invariants. Validate the relationship between fields before deriving metrics from them.

See the Pipetrics August 2026 product update for the other improvements released alongside this fix.

On this page