vectordotdev/vector · error
no default output
Error message
no default output
What it means
`default_output_mut` unconditionally unwraps `self.default_output` and panics with "no default output" if it is absent. The library treats a `SourceSender` without a default output as an invalid state: callers like `send_event`/`send_batch` require the default output created during construction, so its absence is an internal invariant violation.
Solutions
- Create the sender with a default output (e.g. `SourceSender::new()` or the `source_with_sender` helper) before sending events.
- Use named outputs exclusively (`add_output`/`send_batch_named`) if your topology intentionally has no default output.
- Check that you are not reusing a `SourceSender` whose outputs were already taken/moved.
- Update the library call path so `default_output_mut` is only reached on senders known to have a default output.
Example fix
// before let (sender, _) = some_custom_constructor_without_default(); sender.send_event(event).await?; // panics: no default output // after let (mut sender, receiver) = SourceSender::new(); sender.send_event(event).await?;
Defensive patterns
Strategy: type-guard
Validate before calling
// Before sending, confirm the sender exposes the default output assert!(sender.default_output.is_some(), "SourceSender has no default output; call SourceSender::new() first");
Type guard
fn has_default_output(sender: &SourceSender) -> bool {
// if the field is private, track it at your call site:
// keep an Option<SourceSender> and only unwrap after construction with a default output
true // replace with an accessor when available
} Try / catch
// Rust: this is a panic, guard the call site
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
// any use of default_output_mut via send_event
}));
if result.is_err() { /* sender was misconstructed: rebuild it */ } Prevention
- Always construct sources through source_with_sender / SourceSender::new so a default output exists.
- Never hand-roll a SourceSender struct literal; use its constructors.
- If your source only needs named outputs, never touch default-output APIs.
- Add a debug_assert that a default output exists before the send loop starts.
When it happens
Trigger: Constructing or obtaining a `SourceSender` whose `default_output` field is `None` (e.g. a sender built via paths that never call the default-output-producing constructor, or after the output was consumed/replaced) and then invoking any method that calls `default_output_mut` — `send_event`, `send_batch`, or `add_outputs`-related default-output access via `source_with_sender`.
Common situations: Custom Rust sources wiring a `SourceSender` by hand instead of using `SourceSender::new`/`source_with_sender`; refactors that changed the constructor without updating all send paths; using a sender after its default output was moved out.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- unknown output
- can't run runner twice
- Couldn't broadcast config changes.
- Encountered a connection-time error during runtime
- error creating request
AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16).
Data as JSON: /api/errors/b79af43b4731e8ef.
Report an issue: GitHub.
Appendix: source
Thrown at lib/vector-core/src/source_sender/sender.rs:247
output_id,
None,
None,
);
let recv = recv.into_stream().map(move |mut item| {
item.events.iter_events_mut().for_each(|mut event| {
let metadata = event.metadata_mut();
metadata.update_status(status);
metadata.update_sources();
});
item
});
self.named_outputs.insert(name, output);
recv
}
/// Get a mutable reference to the default output, panicking if none exists.
const fn default_output_mut(&mut self) -> &mut Output {
self.default_output.as_mut().expect("no default output")
}
/// Send an event to the default output.
///
/// This internally handles emitting [EventsSent] and [ComponentEventsDropped] events.
pub async fn send_event(&mut self, event: impl Into<EventArray>) -> Result<(), SendError> {
self.default_output_mut().send_event(event).await
}
/// Send a stream of events to the default output.
///
/// This internally handles emitting [EventsSent] and [ComponentEventsDropped] events.
pub async fn send_event_stream<S, E>(&mut self, events: S) -> Result<(), SendError>
where
S: Stream<Item = E> + Unpin,
E: Into<Event> + ByteSizeOf,
{
self.default_output_mut().send_event_stream(events).awaitView on GitHub (pinned to bdb87aeaa4)