vectordotdev/vector · critical

`error` should be an i64

Error message

`error` should be an i64

What it means

The datadog_traces sink computes APM statistics (hits, error counts, duration distributions) from each span's fields. update() reads span['error'] expecting Value::Integer or absent (absent defaults to 0); any other Value type - Boolean(true), Float, String, Map, etc. - hits the catch-all arm and panics, taking down the sink task. The Datadog span contract defines error as an integer flag (0/1), so a present-but-non-integer value means the span layout is not what the sink expects.

Source

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

            None => {
                let mut gs = GroupedStats::new();
                Bucket::update(span, weight, is_top, &mut gs);
                self.data.insert(aggkey, gs);
            }
        }
    }

    /// 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. Route traces into the sink through the supported path (datadog_agent source, or OTLP with Vector's Datadog span normalization) and do not mutate span-internal fields in transforms
  2. If spans are built/modified programmatically, always set error as Value::Integer(0 or 1), never bool/string/float
  3. Upgrade Vector - span field typing fixes have landed across releases; check the changelog for datadog traces/apm stats
  4. If it persists, capture a sanitized span JSON that reproduces it and file an issue

Example fix

// before: building spans with a boolean error flag
span.insert("error", Value::Boolean(true)); // -> panic in apm stats

// after: Datadog APM stats require i64
span.insert("error", Value::Integer(1));
Defensive patterns

Strategy: validation

Validate before calling

// If you build or mutate span maps before the datadog_traces sink:
match span.get("error") {
    None | Some(Value::Integer(_)) => {}
    Some(_) => { span.insert("error", Value::Integer(0)); /* normalize */ }
}

Type guard

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

Prevention

When it happens

Trigger: A trace event reaches the datadog_traces sink whose span map carries 'error' as a non-integer, e.g. true (bool), "1" (string), or 1.0 (float). Common when spans were produced or mutated outside the canonical Datadog pipeline - OTLP ingestion with custom field mapping, remap/transforms touching span internals, or hand-built trace events in tests.

Common situations: Feeding datadog_traces from sources other than the datadog_agent source without full field normalization; VRL or Lua transforms rewriting span fields with non-integer types; version changes in the OTLP-to-Datadog span mapping; clients sending non-standard 'error' attribute types.

Related errors


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