vectordotdev/vector · error

a sink must always have an external resource

Error message

a sink must always have an external resource

What it means

This panic fires in Vector's component validation runner when building the external resource for a sink. Every sink under validation is expected to yield a Some(external_resource) from its builder; the runner creates an mpsc channel so the resource can deliver the sink's output events back to the validator. A None here means the sink framework's contract (a sink always exposes an external resource for validation) was broken, so the code aborts via expect rather than proceeding without a way to observe sink output.

Solutions

  1. Check the sink's builder/validate path and ensure it always constructs and returns an ExternalResource (never None) for sinks.
  2. Verify you are calling run_validation with a sink config, not a source or transform config.
  3. If you recently refactored src/components/validation, restore the code path that wires resource.spawn_as_output with the mpsc channel.

Example fix

// before
let resource = maybe_external_resource.expect("a sink must always have an external resource");
// after
let resource = maybe_external_resource.unwrap_or_else(|| {
    panic!("sink {} did not provide an external resource for validation", sink_name)
});
Defensive patterns

Strategy: validation

Validate before calling

assert!(sink_resource.is_some(), "sink {:?} must expose an external resource for validation", component_id);

Type guard

fn has_external_resource(r: &Option<ExternalResource>) -> bool { r.is_some() }

Prevention

When it happens

Trigger: Calling run_validation on a sink whose registered builder returns None for external_resource, or validating an object that is not actually a sink but was passed down the sink validation path. In practice only reachable by adding/modifying a sink whose ExternalResource construction was skipped or made conditional.

Common situations: A developer adds a new sink or refactors sink build code and forgets to construct/return the external resource in the validation-specific build path; a custom sink integration test harness mislabels a source/transform as a sink.

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

Appendix: source

Thrown at src/components/validation/runner/mod.rs:490

            Ok((
                RunnerInput::External(tx),
                RunnerOutput::Controlled,
                maybe_encoder,
            ))
        }
        ComponentType::Transform => {
            // Transforms have no external resources.
            Ok((RunnerInput::Controlled, RunnerOutput::Controlled, None))
        }
        ComponentType::Sink => {
            // As an external resource for a sink, we create a channel that the validation runner
            // uses to collect the output events from the external resource. We don't care if the sink
            // pushes those output events to the external resource, or if the external resource
            // pulls them from the sink: we just care about getting them from the external resource.
            let (tx, rx) = mpsc::channel(1024);
            let resource =
                maybe_external_resource.expect("a sink must always have an external resource");

            resource.spawn_as_output(
                tx,
                output_task_coordinator,
                test_case.events.clone(),
                runner_metrics,
                configuration.log_namespace(),
            )?;

            Ok((
                RunnerInput::Controlled,
                RunnerOutput::External(rx),
                maybe_encoder,
            ))
        }
    }
}

View on GitHub (pinned to bdb87aeaa4)