vectordotdev/vector · critical
Pausing unknown sink from fanout: {id}
Error message
Pausing unknown sink from fanout: {id} What it means
Handling ControlMessage::Pause, Fanout::pause() looks up the sink by ComponentKey and panics when the key is absent. Pausing is only valid for a sink the fanout knows: the topology pauses a sink (taking its sender) right before replacing it during a rebuild. An unknown key means the control protocol was violated - pausing something that was never added or was already removed.
Source
Thrown at lib/vector-core/src/fanout.rs:112
sender.replace(Sender::new(sink)).is_none(),
"Replacing existing sink is not valid: {id}"
);
}
None => panic!("Replacing unknown sink from fanout: {id}"),
}
}
fn pause(&mut self, id: &ComponentKey) {
match self.senders.get_mut(id) {
Some(sender) => {
// A sink must be known and present to be replaced, otherwise an invalid sequence of
// control operations has been applied.
assert!(
sender.take().is_some(),
"Pausing nonexistent sink is not valid: {id}"
);
}
None => panic!("Pausing unknown sink from fanout: {id}"),
}
}
/// Waits for the next control message and applies it.
///
/// Returns `true` if a message was processed, `false` if the control
/// channel was closed.
pub async fn recv_control_message(&mut self) -> bool {
match self.control_channel.recv().await {
Some(msg) => {
self.apply_control_message(msg);
true
}
None => false,
}
}
/// Apply a control message directly against this instance.View on GitHub (pinned to 3708c39b12)
Solutions
- Upgrade Vector - pause/replace sequencing bugs in the fanout have been fixed upstream; verify against the release changelog
- If it reproduces, file an issue with the reload sequence (before/after configs) and debug logs of ControlMessage traffic
- Avoid reloading configs that simultaneously remove and re-add the same sink id; restart instead
- For embedders: track added ids and emit at most one Pause per id, strictly between its Add and its Remove/Replace
Defensive patterns
Strategy: validation
Validate before calling
// Before pausing, confirm the sink is still registered in your orchestration view
// and that you have not already sent Remove for it:
if registered.contains(&id) && !removed.contains(&id) {
control_tx.send(ControlMessage::Pause(id));
} Prevention
- Never emit Pause for a sink id that was Removed or never Added
- Emit at most one Pause per id between Add and Replace/Remove
- Avoid single reloads that both remove and re-add the same sink id; split or restart
- Test reload sequences against a staging topology under traffic
When it happens
Trigger: A ControlMessage::Pause(id) processed after ControlMessage::Remove(id), or for an id that never had a successful Add; the None arm of senders.get_mut(id) is hit and the panic fires. Occurs mid-reload when sink sets are computed inconsistently.
Common situations: Config reloads that remove and re-add sinks in one operation on older Vector builds; unit tests of topology rebuilding that exercise pause/replace with stale ids; custom orchestrators wrapping Vector's topology API and emitting duplicate Pause messages.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Replacing unknown sink from fanout: {id}
- join error or bad poll
- source output misconfigured - output for port {:?} missing
- errors ignored
- path and query should never fail to parse
AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20).
Data as JSON: /api/errors/fa1696b693c30a89.
Report an issue: GitHub.