vectordotdev/vector · error
Failed type coercion, {self:?} is not a Sink
Error message
Failed type coercion, {self:?} is not a Sink What it means
VectorSink is an enum with exactly two shapes: Sink (a boxed futures::Sink<EventArray>) and Stream (a boxed StreamSink<EventArray>). Most modern Vector sinks are built as VectorSink::Stream; into_sink() unwraps the Sink variant and panics on anything else. The panic is documented on the method: it is a programming error to call into_sink() on a stream-shaped sink.
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 3708c39b12)
Solutions
- Use the shape-agnostic VectorSink::run(input) which handles both variants
- Match on the enum and call into_sink() only in the VectorSink::Sink arm, using into_stream() otherwise
- Guard with matches!(sink, VectorSink::Sink(_)) before unwrapping
Example fix
// before
let sink = vector_sink.into_sink(); // panics for Stream variant
// after
match vector_sink {
VectorSink::Sink(_) => { let s = vector_sink.into_sink(); /* ... */ }
VectorSink::Stream(_) => { let s = vector_sink.into_stream(); /* ... */ }
} Defensive patterns
Strategy: type-guard
Validate before calling
if matches!(vector_sink, VectorSink::Sink(_)) {
let s = vector_sink.into_sink(); // safe
} else {
let s = vector_sink.into_stream();
} Type guard
fn is_sink_variant(v: &VectorSink) -> bool {
matches!(v, VectorSink::Sink(_))
} Prevention
- Prefer VectorSink::run(input), which handles both variants without coercion
- Never assume a third-party sink's shape; match on the enum
- Write wrapper utilities generically over VectorSink rather than over one variant
When it happens
Trigger: Calling sink.into_sink() on a VectorSink constructed via VectorSink::Stream / from_event_streamsink - typical in generic test utilities or wrapper code that assumes every sink implements futures::Sink.
Common situations: Custom sink wrappers or benches written against the Sink shape while the wrapped sink (e.g. HTTP-based Vector sinks) returns the Stream variant; code migrated from older Vector where more sinks were Sink-shaped.
Related errors
- Failed type coercion, {self:?} is not a Stream
- path and query should never fail to parse
- Failed type coercion, {self:?} is not a log event
- Failed type coercion, {self:?} is not a metric
- Failed type coercion, {self:?} is not a log reference
AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20).
Data as JSON: /api/errors/7a8aca70844c34f3.
Report an issue: GitHub.