vectordotdev/vector · error

inner value must be a map

Error message

inner value must be a map

What it means

TraceEvent is a newtype over LogEvent, and into_parts() assumes the inner event value is a Value::Map, calling value.into_object().expect("inner value must be a map") (lib/vector-core/src/event/trace.rs). LogEvent is normally always constructed with a map (from_map/from_parts), so this panic fires only when a TraceEvent was materialized through a path that can hold a non-map value — e.g. deserializing a scalar into the inner LogEvent — violating the newtype's invariant.

Source

Thrown at lib/vector-core/src/event/trace.rs:28

use vrl::path::PathParseError;

use super::{
    BatchNotifier, EstimatedJsonEncodedSizeOf, EventFinalizer, EventFinalizers, EventMetadata,
    Finalizable, LogEvent, MergeFinalizable, ObjectMap, Value,
};

/// Traces are a newtype of `LogEvent`
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct TraceEvent(LogEvent);

impl TraceEvent {
    /// Convert a `TraceEvent` into a tuple of its components
    /// # Panics
    ///
    /// Panics if the fields of the `TraceEvent` are not a `Value::Map`.
    pub fn into_parts(self) -> (ObjectMap, EventMetadata) {
        let (value, metadata) = self.0.into_parts();
        let map = value.into_object().expect("inner value must be a map");
        (map, metadata)
    }

    pub fn from_parts(fields: ObjectMap, metadata: EventMetadata) -> Self {
        Self(LogEvent::from_map(fields, metadata))
    }

    pub fn value(&self) -> &Value {
        self.0.value()
    }

    pub fn value_mut(&mut self) -> &mut Value {
        self.0.value_mut()
    }

    pub fn metadata(&self) -> &EventMetadata {
        self.0.metadata()
    }

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Validate the payload shape before deserializing: require the top-level JSON value to be an object before constructing a TraceEvent
  2. Build TraceEvents only via TraceEvent::from_parts(ObjectMap, metadata) or insertion APIs that keep the map invariant
  3. If you deserialize untrusted data, match on the Value first and reject non-map values with an error instead of proceeding

Example fix

// before
let (map, metadata) = trace.into_parts();

// after
let (value, metadata) = trace.into_parts_value();
let Some(map) = value.into_object() else {
    return Err("trace event fields must be an object");
};
Defensive patterns

Strategy: type-guard

Validate before calling

// Before calling into_parts, confirm the payload shape if it came from external data
if !raw_json.is_object() {
    return Err(DecodeError::new("trace payload must be a JSON object"));
}

Type guard

fn trace_is_map(trace: &TraceEvent) -> bool {
    matches!(trace.value(), Value::Map(_))
}

Prevention

When it happens

Trigger: Calling TraceEvent::into_parts() on a TraceEvent whose inner LogEvent value is not Value::Map — typically a TraceEvent built via serde Deserialize from JSON that is a string/number/array rather than an object, or via LogEvent::new with a manually replaced scalar value. from_parts()-built events can never trigger it.

Common situations: Test code or embedding code that deserializes TraceEvents from payloads where the trace body is not a JSON object; interop code that converts arbitrary Values into TraceEvent without a map check. End-user Vector configs do not hit this in normal operation — it is an API-misuse/serialization-shape panic.

Related errors


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