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

  1. Create the sender with a default output (e.g. `SourceSender::new()` or the `source_with_sender` helper) before sending events.
  2. Use named outputs exclusively (`add_output`/`send_batch_named`) if your topology intentionally has no default output.
  3. Check that you are not reusing a `SourceSender` whose outputs were already taken/moved.
  4. 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

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


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).await

View on GitHub (pinned to bdb87aeaa4)