vectordotdev/vector · error

early buffer was already consumed

Error message

early buffer was already consumed

What it means

`consume_early_buffer` takes the buffered early log events out of the static BUFFER via `.take()`. `take()` returns `None` if the buffer is already `None`, meaning the early buffer was consumed once before; the `expect` then panics. Per its doc comment, consuming twice is a caller-contract violation.

Solutions

  1. Ensure `stop_early_buffering` is called exactly once per process lifetime
  2. Guard the stop call with an idempotency check (e.g. a OnceLock/atomic flag)
  3. Use `consume_early_buffer`'s caller contract: check `should_process_tracing_event`/buffer state before consuming
  4. In tests, run each case in a separate process or serialize setup

Example fix

// before
stop_early_buffering();
stop_early_buffering(); // panics
// after
static STOPPED: OnceLock<()> = OnceLock::new();
if STOPPED.set(()).is_ok() {
    stop_early_buffering();
}
Defensive patterns

Strategy: validation

Validate before calling

// idempotent guard around consume
static CONSUMED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
if !CONSUMED.swap(true, std::sync::atomic::Ordering::SeqCst) {
    stop_early_buffering();
}

Prevention

When it happens

Trigger: Calling `consume_early_buffer` (through `stop_early_buffering`) more than once — e.g. `stop_early_buffering` invoked twice, or after early buffering was already stopped and consumed.

Common situations: Duplicate shutdown/initialization sequences in tests that call `stop_early_buffering` per test without isolation; race conditions where two tasks both attempt to stop early buffering concurrently.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/d1d0e292033e36d9. Report an issue: GitHub.

Appendix: source

Thrown at src/trace.rs:193

/// Attempts to broadcast an event to subscribers.
///
/// If no subscribers are connected, this does nothing.
fn try_broadcast_event(log: LogEvent) {
    if let Some(sender) = maybe_get_trace_sender() {
        _ = sender.send(log);
    }
}

/// Consumes the early buffered events.
///
/// # Panics
///
/// If the early buffered events have already been consumed, this function will panic.
fn consume_early_buffer() -> Vec<LogEvent> {
    get_early_buffer()
        .take()
        .expect("early buffer was already consumed")
}

/// Gets or creates a trace sender for sending internal log events.
fn get_trace_sender() -> &'static broadcast::Sender<LogEvent> {
    SENDER.get_or_init(|| broadcast::channel(99).0)
}

/// Attempts to get the trace sender for sending internal log events.
///
/// If the trace sender has not yet been created, `None` is returned.
fn maybe_get_trace_sender() -> Option<&'static broadcast::Sender<LogEvent>> {
    SENDER.get()
}

/// Creates a trace receiver that receives internal log events.
///
/// This will create a trace sender if one did not already exist.
fn get_trace_receiver() -> broadcast::Receiver<LogEvent> {

View on GitHub (pinned to bdb87aeaa4)