{"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/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/lib/vector-core/src/sink.rs#L31-L67","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Match on the VectorSink variant and call into_sink only for VectorSink::Sink","Use VectorSink::run / run_events instead of unwrapping, which handles both variants","In test code, construct the sink explicitly with VectorSink::from_event_sink to guarantee the Sink variant"],"exampleFix":"// before\nlet sink = vector_sink.into_sink();\n// after\nmatch vector_sink {\n    VectorSink::Sink(s) => /* use s */,\n    VectorSink::Stream(_) => panic!(\"expected event sink\"),\n}\n// or generically:\nvector_sink.run(input).await?;","handlingStrategy":"type-guard","validationCode":"assert!(matches!(vector_sink, VectorSink::Sink(_)), \"expected event sink, got {:?}\", vector_sink);","typeGuard":"fn as_event_sink(s: VectorSink) -> Option<Box<dyn Sink<EventArray, Error = ()> + Send + Unpin>> {\n    match s {\n        VectorSink::Sink(sink) => Some(sink),\n        _ => None,\n    }\n}","tryCatchPattern":null,"preventionTips":["Prefer VectorSink::run/run_events over into_sink/into_stream unwrapping","Check whether the component builds its sink via from_event_sink vs from_event_streamsink before unwrapping","Keep test harnesses variant-agnostic by dispatching on the enum"],"tags":["rust","panic","sink","type-coercion"],"backgroundTag":"type-mismatch","analyzedSha":"bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}