Skip to content

Trace aggregation behavior change in agent: nightly failure 2026-09-30 potential root cause. #2723

Open

Description

@webern

I need to toss this over the fence because I'm looking at a different issue that is happening right now, and in case I don't get back to this, the investigation and conclusions below seem pretty plausible and actionable.

Nightly runs against datadog-agent main-ish in order to catch integration issues before they land in tagged release candidates. A recent change to trace behavior causes three correctness tests to fail. When @jszwedko re-ran the tests, apparently (according to Opus, below, unverified by me) it no longer ran the same commit from datadog-agent and instead ran with a stable tag (we should also fix that!)


Opus analysis:

Root cause analysis: nightly pipeline 141153981

This is a real integration break (class 2), not a flake. Jesse's rerun passed only because it ran against the stable Agent instead of the nightly one.

There were 2 failing tests, not 3: test-correctness-otlp-traces and test-correctness-otlp-traces-ets. Each failed all 3 auto-retry attempts, in child pipeline 141155097, with the same message every time:

Number of aggregation keys do not match: 119 (baseline) vs 113 (comparison)

1. The Agent change behind the failure

The cause is datadog-agent a458d1f7511, "trace/stats: clamp future span buckets to the current time bucket" (#56608, @ajgajg1134 , merged 09-22). No released tag contains it yet, so it first ships in 7.85.

  • Before the change: a span whose end time is in the future lands in a future stats bucket. That bucket isn't flushed until the wall clock reaches it.
  • After the change: the bucket is clamped to the current time bucket, so the span is counted and flushed right away.

ADP's port at lib/saluki-components/src/transforms/apm_stats/span_concentrator.rs:329 still has the old logic:

let btime = (end - end % self.bsize).max(self.oldest_ts);

2. Evidence from the failed run's artifacts

The failed run used Agent 7.85.0-devel+git.808.70c956a. The OTLP span timestamps come from lading's random traces generator, and many are centuries in the future.

Baseline (nightly Agent alone) Comparison (Agent + ADP)
Spans with end time in the past 414 414
Spans with end time in the future 3682 3682
Stats hits flushed 4096 (all spans) 414 (past spans only)
Aggregation groups 119 113
  • All 4096 spans matched between the two sides, apart from the already-ignored meta.http.status_code. The difference is only in stats.
  • The 6 extra baseline groups are status-code combinations that only appear among the future-dated spans. Examples: api-gateway GET /api/v1/products 409 and 301, and product-service ListProducts gRPC 6, 12 and 15.
  • Only these two tests compare stats. The other four otlp-traces-* cases set otlp_direct_analysis_mode: true, which skips the stats comparison.

3. Why the rerun passed: a race on the image tag

Every scheduled pipeline on the same commit pushes the same mutable tag, bundled-agent-adp:${CI_COMMIT_SHA} (see build-bundled-agent-adp-image in .gitlab/e2e.yml). Three schedules ran on 4cd2f4aa:

Time (UTC) Pipeline Agent image pushed
04:27:02 Fuzzing (141153980) stable agent:7.83.3-full
04:27:12 Nightly (141153981) nightly agent-dev@sha256:4b23… (won by 10s)
08:17 Nightly SMP (141176166) stable agent:7.83.3-full (overwrote the tag)
12:41 Jesse's rerun ran against 7.83.3, so it passed

The rerun's own logs confirm it: Starting Datadog Agent v7.83.3, plus an ADP build time of 08:03, which belongs to the SMP pipeline's build.

4. The nightly has been failing silently since 09-26

I checked which Agent each recent nightly actually tested:

Date Agent actually tested otlp-traces
09-24, 09-25, 09-28 7.83.2 (stable) pass
09-26, 09-27, 09-29 (first attempt), 09-30 7.85.0-devel (nightly) fail (same message)
09-29 rerun 7.83.3 (stable) pass

Every run that got the nightly Agent failed; every recent pass tested a stable Agent. Runs from before 09-24 no longer have artifacts, so I couldn't check them.

Recommended fixes

  1. Make the nightly test the Agent it says it tests. The nightly bundled image should use a tag that other pipelines on the same commit can't overwrite. For example, include CI_PIPELINE_ID or a -nightly suffix in the tag, or pass the pushed digest down to the child pipeline. Without this, ~half of nightlies quietly test stable, and retries can "fix" real failures.
  2. Bring ADP in line with the new Agent behaviour. Port the clamp into add_span_internal by passing now through. This is also a real memory-retention bug in ADP: future-dated buckets pile up until the clock catches up, which is exactly what the Agent PR fixed.
  3. Work around the pinned Agent version. Main pins Agent 7.83.3, so porting the clamp alone would flip the failure onto main (ADP 119 vs Agent 113). The simplest fix that works with both versions is to give these two tests a corpus with no future-dated spans; both Agent behaviours then agree. Clamping into the current bucket instead of dropping only changes the outcome for future-dated spans. Once the pin reaches 7.85 or later, the random timestamps can come back to cover the clamp.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions