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
- Use the canonical ingestion path (datadog_agent source / OTLP with Datadog normalization) so durations are decoded as integers
- When constructing spans, insert duration as Value::Integer(nanoseconds)
- Upgrade Vector and review the changelog for datadog traces fixes
- 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
- Avoid JSON round-trips of spans between source and sink (floats replace large i64 durations)
- Insert duration as Value::Integer nanoseconds when building spans
- Keep trace pipelines native (no generic log transforms in the path)
- Verify span field types in staging with a console sink tap before enabling apm stats
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
- `error` should be an i64
- `parent_id` should be an i64
- Failed type coercion, {self:?} is not a trace event
- Traces are not supported.
- message is required (make sure the "message" semantic meanin
AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20).
Data as JSON: /api/errors/e6cf5fc5373f8898.
Report an issue: GitHub.