vectordotdev/vector · error

Failed type coercion

Error message

Failed type coercion, {self:?} is not a Sink

What it means

VectorSink::into_sink unwraps the VectorSink enum into its Sink variant (a Box<dyn Sink<EventArray>>), panicking if the sink was built as a Stream variant instead. VectorSink is built from a component's sink implementation, so this panic means the caller hardcoded an assumption about which style of sink the component builds.

Solutions

  1. Match on the VectorSink variant and call into_sink only for VectorSink::Sink
  2. Use VectorSink::run / run_events instead of unwrapping, which handles both variants
  3. In test code, construct the sink explicitly with VectorSink::from_event_sink to guarantee the Sink variant

Example fix

// before
let sink = vector_sink.into_sink();
// after
match vector_sink {
    VectorSink::Sink(s) => /* use s */,
    VectorSink::Stream(_) => panic!("expected event sink"),
}
// or generically:
vector_sink.run(input).await?;
Defensive patterns

Strategy: type-guard

Validate before calling

assert!(matches!(vector_sink, VectorSink::Sink(_)), "expected event sink, got {:?}", vector_sink);

Type guard

fn as_event_sink(s: VectorSink) -> Option<Box<dyn Sink<EventArray, Error = ()> + Send + Unpin>> {
    match s {
        VectorSink::Sink(sink) => Some(sink),
        _ => None,
    }
}

Prevention

When it happens

Trigger: Calling VectorSink::into_sink on a sink built via VectorSink::from_event_streamsink / from_event_stream (the Stream variant), e.g. in custom sink drivers or tests that assume an event sink.

Common situations: Custom Vector builds or test harnesses that take a component's VectorSink and force it into a futures::Sink, while the component (most modern built-ins are stream-based) returned a StreamSink.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/7a8aca70844c34f3. Report an issue: GitHub.

Appendix: source

Thrown at lib/vector-core/src/sink.rs:49

    ///
    /// See `VectorSink::run` for errors.
    pub async fn run_events<I>(self, input: I) -> Result<(), ()>
    where
        I: IntoIterator<Item = Event> + Send,
        I::IntoIter: Send,
    {
        self.run(stream::iter(input).map(Into::into)).await
    }

    /// Converts `VectorSink` into a `futures::Sink`
    ///
    /// # Panics
    ///
    /// This function will panic if the self instance is not `VectorSink::Sink`.
    pub fn into_sink(self) -> Box<dyn Sink<EventArray, Error = ()> + Send + Unpin> {
        match self {
            Self::Sink(sink) => sink,
            _ => panic!("Failed type coercion, {self:?} is not a Sink"),
        }
    }

    /// Converts `VectorSink` into a `StreamSink`
    ///
    /// # Panics
    ///
    /// This function will panic if the self instance is not `VectorSink::Stream`.
    pub fn into_stream(self) -> Box<dyn StreamSink<EventArray> + Send> {
        match self {
            Self::Stream(stream) => stream,
            _ => panic!("Failed type coercion, {self:?} is not a Stream"),
        }
    }

    /// Converts an event sink into a `VectorSink`
    ///
    /// Deprecated in favor of `VectorSink::from_event_streamsink`. See [vector/9261]

View on GitHub (pinned to bdb87aeaa4)