vectordotdev/vector · critical

`duration` should be an i64

Error message

`duration` should be an i64

What it means

In the datadog_traces sink's APM stats bucket update, span['duration'] must be Value::Integer (nanoseconds) or absent (treated as 0); any other Value variant panics with '`duration` should be an i64'. The duration feeds both the total duration sum and the ok/err distributions, which are DDSketch-backed and expect f64 built from integers.

Source

Thrown at src/sinks/datadog/traces/apm_stats/bucket.rs:182

    /// Update a bucket with a new span. Computed statistics include the number of hits and the actual distribution of
    /// execution time, with isolated measurements for spans flagged as errored and spans without error.
    fn update(span: &ObjectMap, weight: f64, is_top: bool, gs: &mut GroupedStats) {
        is_top.then(|| {
            gs.top_level_hits += weight;
        });
        gs.hits += weight;
        let error = match span.get("error") {
            Some(Value::Integer(val)) => *val,
            None => 0,
            _ => panic!("`error` should be an i64"),
        };
        if error != 0 {
            gs.errors += weight;
        }
        let duration = match span.get("duration") {
            Some(Value::Integer(val)) => *val,
            None => 0,
            _ => panic!("`duration` should be an i64"),
        };
        gs.duration += (duration as f64) * weight;
        if error != 0 {
            gs.err_distribution.insert(duration as f64)
        } else {
            gs.ok_distribution.insert(duration as f64)
        }
    }
}

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Use the canonical ingestion path (datadog_agent source / OTLP with Datadog normalization) so durations are decoded as integers
  2. When constructing spans, insert duration as Value::Integer(nanoseconds)
  3. Upgrade Vector and review the changelog for datadog traces fixes
  4. Inspect the offending span (dump events with a console sink tapped before the datadog sink) to find which producer emits the wrong type

Example fix

// before
span.insert("duration", Value::Float(1.5e6)); // -> panic

// after: duration is i64 nanoseconds
span.insert("duration", Value::Integer(1_500_000));
Defensive patterns

Strategy: validation

Validate before calling

match span.get("duration") {
    None | Some(Value::Integer(_)) => {}
    Some(other) => {
        // normalize to i64 nanoseconds before the sink sees it
        let ns = coerce_to_i64_ns(other).unwrap_or(0);
        span.insert("duration", Value::Integer(ns));
    }
}

Type guard

fn span_duration_is_i64(span: &ObjectMap) -> bool {
    matches!(span.get("duration"), None | Some(Value::Integer(_)))
}

Prevention

When it happens

Trigger: A span arriving with 'duration' as a float, string, or bool - e.g. an OTLP span whose nanosecond duration was serialized as a JSON number that decoded to f64, or a transform that rewrote duration into a string. Absence is safe; presence with the wrong type panics.

Common situations: Non-Datadog-native trace sources feeding datadog_traces; serialization round-trips (JSON) that turn large i64 durations into floats; custom field mappings that mis-type duration; older Vector versions with incomplete span normalization.

Related errors


AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20). Data as JSON: /api/errors/e6cf5fc5373f8898. Report an issue: GitHub.