vectordotdev/vector · critical
output for default port required for task transforms
Error message
output for default port required for task transforms
What it means
When building a task (blocking) transform, the builder looks for an output with port == None (the default output) and .expect()s one exists, since task transforms may only write to the default output. Panicking here means a task transform's Outputs list lacks a default-port entry — an internal invariant or invalid component implementation.
Solutions
- Ensure the task transform declares exactly one default (unnamed port) output
- If the transform needs multiple outputs, do not build it as a task transform (use a regular/fan-out transform)
- Fix the component's outputs() implementation to include a None-port Output
- Report to the component author if triggered by a third-party transform
Example fix
// before
outputs: vec![Output::new(Port("secondary"), schema)] // no default port
// after
outputs: vec![Output::default(Port(None), schema)] // include default output Defensive patterns
Strategy: type-guard
Validate before calling
// config-time guard: task transforms must expose a default output assert!(outputs.iter().any(|o| o.port.is_none()), "task transform lacks default output");
Type guard
fn has_default_output(outputs: &[Output]) -> bool { outputs.iter().any(|o| o.port.is_none()) } Prevention
- Implement outputs() for task transforms with a single unnamed default output
- Use fan-out transforms, not task transforms, for multi-output components
- Validate transform output contracts in component tests
When it happens
Trigger: A custom Transform implementation registered as a task transform that only declares named-port outputs (e.g. a route-style multi-output) without a default output; corrupted output metadata from a misbehaving component.
Common situations: Developers implementing custom task transforms in plugins/forks and wiring them to multiple named outputs; incorrect transform registration that marks a fan-out transform as a task transform.
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
- allowed_lateness_ms validated to fit in i64 in…
- cant ever be empty
- event-time path requires AggregateConfig.event_time
- interval_ms validated to fit in i64 in Aggregate::new
- max_future_ms validated to fit in i64 in Aggregate::new
AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16).
Data as JSON: /api/errors/fe524ce1ee0c30ac.
Report an issue: GitHub.
Appendix: source
Thrown at src/topology/builder.rs:955
.filter(move |events| ready(filter_events_type(events, input_type)))
.inspect(move |events| {
events_received.emit(CountByteSize(
events.len(),
events.estimated_json_encoded_size_of(),
))
});
let events_sent = register!(EventsSent::from(internal_event::Output(None)));
let output_id = Arc::new(OutputId {
component: key.clone(),
port: None,
});
let latency_recorder = LatencyRecorder::new(self.config.global.latency_ewma_alpha);
// Task transforms can only write to the default output, so only a single schema def map is needed
let schema_definition_map = outputs
.iter()
.find(|x| x.port.is_none())
.expect("output for default port required for task transforms")
.log_schema_definitions
.clone()
.into_iter()
.map(|(key, value)| (key, Arc::new(value)))
.collect();
let stream = t
.transform(Box::pin(filtered))
.map(move |mut events| {
for event in events.iter_events_mut() {
update_runtime_schema_definition(event, &output_id, &schema_definition_map);
}
let now = Instant::now();
latency_recorder.on_send(&mut events, now);
(events, now)
})
.inspect(move |(events, _): &(EventArray, Instant)| {
events_sent.emit(CountByteSize(View on GitHub (pinned to bdb87aeaa4)