vectordotdev/vector · error

span must already exist!

Error message

span must already exist!

What it means

In the tracing `Layer`'s `on_new_span`, the code looks up the span by id with `ctx.span(id)` and expects it to exist since the callback fires for a newly created span. If the registry returns `None`, the `expect("span must already exist!")` panics — a layer/registry invariant violation.

Solutions

  1. Use this layer with the standard `tracing_subscriber::Registry` it is designed for
  2. Verify layer ordering (registry-based layers must sit above the Registry)
  3. If using a custom subscriber, implement span lookup correctly or skip the extension insert
  4. File a bug with subscriber setup if the standard registry still triggers it

Example fix

// before
let span = ctx.span(id).expect("span must already exist!");
// after
if let Some(span) = ctx.span(id) {
    span.extensions_mut().insert(fields);
}
Defensive patterns

Strategy: type-guard

Type guard

// narrow instead of expect
fn span_fields<S>(ctx: &Context<'_, S>, id: &tracing_core::span::Id) -> Option<SpanFields> {
    ctx.span(id).map(|span| {
        let mut f = SpanFields::default();
        span.extensions_mut().insert(f.clone());
        f
    })
}

Prevention

When it happens

Trigger: A custom `Subscriber`/`Registry` combination where `Context::span(id)` returns `None` for a span id passed to `on_new_span`, e.g. a non-registry subscriber or spans being dropped concurrently with creation.

Common situations: Using this layer with a subscriber other than the tracing Registry it assumes; custom layering where span lifetimes are managed unusually; forks altering registry behavior.

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/747de2061f83cafd. Report an issue: GitHub.

Appendix: source

Thrown at src/trace.rs:356

                        }
                    }
                }
            }
            // Try buffering the event, and if we're not buffering anymore, try to
            // send it along via the trace sender if it's been established.
            if !try_buffer_event(&log) {
                try_broadcast_event(log);
            }
        }
    }

    fn on_new_span(
        &self,
        attrs: &tracing_core::span::Attributes<'_>,
        id: &tracing_core::span::Id,
        ctx: Context<'_, S>,
    ) {
        let span = ctx.span(id).expect("span must already exist!");
        let mut fields = SpanFields::default();
        attrs.values().record(&mut fields);
        span.extensions_mut().insert(fields);
    }
}

#[derive(Default, Debug)]
struct SpanFields(HashMap<&'static str, Value>);

inventory::submit!(SpanField("component_id"));
inventory::submit!(SpanField("component_type"));
inventory::submit!(SpanField("component_kind"));

/// Snapshot of every registered [`SpanField`],
/// materialized once on first access. `inventory` populates submissions before `main`, so the
/// snapshot is guaranteed to capture every entry; the read path on every traced span event is
/// then a single set lookup against this static.
static SPAN_FIELDS: LazyLock<HashSet<&'static str>> =

View on GitHub (pinned to bdb87aeaa4)