{"record":{"id":"03be0d9e06851dd2","repo":"vectordotdev/vector","slug":"a-source-must-always-have-an-external-resource","errorCode":null,"errorMessage":"a source must always have an external resource","messagePattern":"a source must always have an external resource","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/components/validation/runner/mod.rs","lineNumber":470,"sourceCode":") -> Result<(RunnerInput, RunnerOutput, Option<Encoder<encoding::Framer>>), vector_lib::Error> {\n    let component_type = configuration.component_type();\n    let maybe_external_resource = configuration.external_resource(test_case.config_name.as_ref());\n\n    let resource_codec = maybe_external_resource\n        .as_ref()\n        .map(|resource| resource.codec.clone());\n\n    let maybe_encoder = resource_codec.as_ref().map(|codec| codec.into_encoder());\n\n    match component_type {\n        ComponentType::Source => {\n            // As an external resource for a source, we create a channel that the validation runner\n            // uses to send the input events to the external resource. We don't care if the source\n            // pulls those input events or has them pushed in: we just care about getting them to\n            // the external resource.\n            let (tx, rx) = mpsc::channel(1024);\n            let resource =\n                maybe_external_resource.expect(\"a source must always have an external resource\");\n            resource.spawn_as_input(rx, input_task_coordinator, runner_metrics);\n\n            Ok((\n                RunnerInput::External(tx),\n                RunnerOutput::Controlled,\n                maybe_encoder,\n            ))\n        }\n        ComponentType::Transform => {\n            // Transforms have no external resources.\n            Ok((RunnerInput::Controlled, RunnerOutput::Controlled, None))\n        }\n        ComponentType::Sink => {\n            // As an external resource for a sink, we create a channel that the validation runner\n            // uses to collect the output events from the external resource. We don't care if the sink\n            // pushes those output events to the external resource, or if the external resource\n            // pulls them from the sink: we just care about getting them from the external resource.\n            let (tx, rx) = mpsc::channel(1024);","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/src/components/validation/runner/mod.rs#L452-L488","documentation":"build_external_resource requires that every source under validation has an associated external resource; otherwise there is nowhere to deliver input events. The expect fires when the source type did not produce an external resource earlier in the construction, meaning the validation framework's coverage of source kinds is incomplete (a code bug, not a user config error).","triggerScenarios":"run_validation calls build_external_resource for a source whose maybe_external_resource is None — i.e. a source kind not handled by the match that spawns channel/socket-based resources.","commonSituations":"Adding a new source type and running validation before implementing its external-resource support; a refactored match arm that silently skips a source variant.","solutions":["Implement spawn_as_input support / an external resource for the uncovered source kind in the validation framework.","Check the match in build_external_resource and add the missing source variant.","Return a descriptive error naming the source type instead of a bare expect."],"exampleFix":"// before\nlet resource = maybe_external_resource.expect(\"a source must always have an external resource\");\n// after\nlet resource = maybe_external_resource\n    .unwrap_or_else(|| panic!(\"source kind {:?} has no external resource support\", source_type));","handlingStrategy":"validation","validationCode":"// Before running validation, confirm the source kind is supported\nassert!(matches!(source, SourceConfig::File(_) | SourceConfig::Socket(_) /* ... */),\n    \"source kind lacks external-resource support\");","typeGuard":null,"tryCatchPattern":"let resource = maybe_external_resource.unwrap_or_else(||\n    panic!(\"no external resource implemented for this source kind\"));","preventionTips":["Add external-resource support for every new source type before enabling validation.","Keep the build_external_resource match exhaustive with a compile-time-checked enum.","Name the offending source type in the panic message for faster triage."],"tags":["validation","source","panic","internal"],"backgroundTag":"internal-invariant-violation","analyzedSha":"bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}