vectordotdev/vector · error

unknown output

Error message

unknown output

What it means

`setup_inputs` looks up each input's source in the running topology's `outputs` map and panics with "unknown output" if it is missing (src/topology/running.rs:974). During a diff-based reload, every input referenced by a component must have a known output registered in `self.outputs`; a miss means the diff bookkeeping dropped or never registered that output.

Solutions

  1. Verify every component's `inputs` names a component that exists in the new config; fix stale names before reloading.
  2. Ensure `connect_diff` registers all new outputs (via setup_outputs) before setup_inputs runs.
  3. Fall back to a full topology rebuild instead of diff reload if outputs bookkeeping is inconsistent.

Example fix

// config mistake
// before: sink.inputs = ["old_source"]  (source renamed to new_source)
// after:
// source:
//   new_source: ...
// sink:
//   inputs: ["new_source"]
Defensive patterns

Strategy: validation

Validate before calling

// before reload: every input name must exist as a component in the new config
for c in new_config.components() {
    for inp in &c.inputs {
        assert!(new_config.contains_component(inp), "input {inp} of {} missing", c.id());
    }
}

Prevention

When it happens

Trigger: `connect_diff` connecting an input whose producing component was removed or renamed in the new config but still referenced, or whose output was never added to `self.outputs` during the diff application.

Common situations: Renaming a component in the config while other components still list the old name in their `inputs`; reload races where outputs were not migrated.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at src/topology/running.rs:974

        key: &ComponentKey,
        diff: &ConfigDiff,
        new_pieces: &mut builder::TopologyPieces,
    ) {
        let (tx, inputs) = new_pieces.inputs.remove(key).unwrap();

        let old_inputs = self
            .config
            .inputs_for_node(key)
            .into_iter()
            .flatten()
            .cloned()
            .collect::<HashSet<_>>();

        let new_inputs = inputs.iter().cloned().collect::<HashSet<_>>();
        let inputs_to_add = &new_inputs - &old_inputs;

        for input in inputs {
            let output = self.outputs.get_mut(&input).expect("unknown output");

            if diff.contains(&input.component) || inputs_to_add.contains(&input) {
                // If the input we're connecting to is changing, that means its outputs will have been
                // recreated, so instead of replacing a paused sink, we have to add it to this new
                // output for the first time, since there's nothing to actually replace at this point.
                debug!(component_id = %key, fanout_id = %input, "Adding component input to fanout.");

                _ = output.send(ControlMessage::Add(key.clone(), tx.clone()));
            } else {
                // We know that if this component is connected to a given input, and neither
                // components were changed, then the output must still exist, which means we paused
                // this component's connection to its output, so we have to replace that connection
                // now:
                debug!(component_id = %key, fanout_id = %input, "Replacing component input in fanout.");

                _ = output.send(ControlMessage::Replace(key.clone(), tx.clone()));
            }
        }

View on GitHub (pinned to bdb87aeaa4)