{"record":{"id":"7a8aca70844c34f3","repo":"vectordotdev/vector","slug":"failed-type-coercion-self-is-not-a-sink","errorCode":null,"errorMessage":"Failed type coercion, {self:?} is not a Sink","messagePattern":"Failed type coercion, (.+?) is not a Sink","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/vector-core/src/sink.rs","lineNumber":49,"sourceCode":"    ///\n    /// See `VectorSink::run` for errors.\n    pub async fn run_events<I>(self, input: I) -> Result<(), ()>\n    where\n        I: IntoIterator<Item = Event> + Send,\n        I::IntoIter: Send,\n    {\n        self.run(stream::iter(input).map(Into::into)).await\n    }\n\n    /// Converts `VectorSink` into a `futures::Sink`\n    ///\n    /// # Panics\n    ///\n    /// This function will panic if the self instance is not `VectorSink::Sink`.\n    pub fn into_sink(self) -> Box<dyn Sink<EventArray, Error = ()> + Send + Unpin> {\n        match self {\n            Self::Sink(sink) => sink,\n            _ => panic!(\"Failed type coercion, {self:?} is not a Sink\"),\n        }\n    }\n\n    /// Converts `VectorSink` into a `StreamSink`\n    ///\n    /// # Panics\n    ///\n    /// This function will panic if the self instance is not `VectorSink::Stream`.\n    pub fn into_stream(self) -> Box<dyn StreamSink<EventArray> + Send> {\n        match self {\n            Self::Stream(stream) => stream,\n            _ => panic!(\"Failed type coercion, {self:?} is not a Stream\"),\n        }\n    }\n\n    /// Converts an event sink into a `VectorSink`\n    ///\n    /// Deprecated in favor of `VectorSink::from_event_streamsink`. See [vector/9261]","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/vectordotdev/vector/blob/3708c39b12a93212ed8b8d7510b4cc7769cb5864/lib/vector-core/src/sink.rs#L31-L67","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet sink = vector_sink.into_sink(); // panics for Stream variant\n\n// after\nmatch vector_sink {\n    VectorSink::Sink(_) => { let s = vector_sink.into_sink(); /* ... */ }\n    VectorSink::Stream(_) => { let s = vector_sink.into_stream(); /* ... */ }\n}","handlingStrategy":"type-guard","validationCode":"if matches!(vector_sink, VectorSink::Sink(_)) {\n    let s = vector_sink.into_sink(); // safe\n} else {\n    let s = vector_sink.into_stream();\n}","typeGuard":"fn is_sink_variant(v: &VectorSink) -> bool {\n    matches!(v, VectorSink::Sink(_))\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["rust","vector","sink","type-coercion","panic"],"backgroundTag":"invalid-type-coercion","analyzedSha":"3708c39b12a93212ed8b8d7510b4cc7769cb5864","analyzedAt":"2026-08-20T07:02:18.786Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}