Hmbown/CodeWhale · error
fleet alert adapter is not configured
Error message
fleet alert adapter {} is not configured What it means
FleetAlertDispatcher::dispatch() routes each FleetAlertEvent through config.routes whose event class matches. Each route names an adapter by string key, and that key must exist in the config.adapters map (kind: slack | webhook | pagerduty entries). If the route's adapter string has no matching adapters entry, dispatch fails immediately with this error.
Solutions
- Open the fleet alerts config and make the route's adapter string byte-identical to an existing key under adapters.
- If the adapter was meant to exist, add the missing adapters entry (Slack{webhook_env}, Webhook{url_env,secret_env}, or PagerDuty{routing_key_env}).
- Remove the stale route if the adapter was retired.
- Until config is fixed, you can set enabled=false or use dry_run=true so dispatch returns early instead of erroring.
Example fix
// before
{"enabled":true,"routes":[{"events":["task_failed"],"adapter":"slack-ops"}],"adapters":{"slack":{"kind":"slack","webhook_env":"SLACK_WEBHOOK_URL"}}}
// after (route key matches adapters key)
{"enabled":true,"routes":[{"events":["task_failed"],"adapter":"slack"}],"adapters":{"slack":{"kind":"slack","webhook_env":"SLACK_WEBHOOK_URL"}}} Defensive patterns
Strategy: validation
Validate before calling
fn validate_alert_config(cfg: &FleetAlertConfig) -> Result<(), String> {
for route in &cfg.routes {
if !cfg.adapters.contains_key(&route.adapter) {
return Err(format!("route references unknown adapter '{}'", route.adapter));
}
}
Ok(())
}
validate_alert_config(&config)?; // before enabling dispatch
Type guard
fn adapter_is_configured(cfg: &FleetAlertConfig, route: &FleetAlertRoute) -> bool {
cfg.adapters.contains_key(&route.adapter)
}
Try / catch
match dispatcher.dispatch(&event) {
Ok(deliveries) => { /* record deliveries */ }
Err(e) if e.to_string().contains("adapter") && e.to_string().contains("not configured") => {
// config defect: log route/adapter names, disable the route, continue the run
}
Err(e) => return Err(e),
} Prevention
- Derive route adapter names from the adapters map (iterate keys) instead of typing them twice.
- Add a config-load-time assertion that every routes[].adapter key exists in adapters.
- Keep alerts config in one file; merging routes and adapters from different sources invites drift.
- Run one dry_run=true dispatch when changing alert config.
When it happens
Trigger: A FleetAlertConfig where routes[].adapter (e.g. "ops-slack") does not match any key in the adapters BTreeMap — typo, renamed adapter, route copied from another config, or adapter entry deleted while the route stayed.
Common situations: Hand-edited fleet alert TOML/JSON config; renaming an adapter key without updating routes; enabling alert routes via config merge where the adapters section comes from a different file; CI configs drifting from local ones.
Related errors
- Fleet alert adapter is not configured
- agent profile path is not a directory
- agent profile provider cannot be empty
- agent profile provider must be a simple provider id
- agent profile tools.posture= would widen permissions; use…
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/5c286cb934fd60f2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/fleet/alerts.rs:133
R: FleetAlertSecretResolver,
{
pub fn new(config: FleetAlertConfig, resolver: R) -> Self {
Self { config, resolver }
}
pub fn dispatch(&self, event: &FleetAlertEvent) -> Result<Vec<FleetAlertDelivery>> {
if !self.config.enabled {
return Ok(Vec::new());
}
let mut deliveries = Vec::new();
for route in self
.config
.routes
.iter()
.filter(|route| route_matches(route, event.class))
{
let adapter = self.config.adapters.get(&route.adapter).ok_or_else(|| {
anyhow!("fleet alert adapter {} is not configured", route.adapter)
})?;
let prepared = prepare_alert(&route.adapter, adapter, event, self.config.dry_run)?;
let sent = if self.config.dry_run {
false
} else {
send_alert(adapter, &prepared.body, &self.resolver)?
};
deliveries.push(FleetAlertDelivery {
adapter: route.adapter.clone(),
event_class: event.class,
dry_run: self.config.dry_run,
sent,
redacted_payload: prepared.redacted_payload,
});
}
Ok(deliveries)
}
}View on GitHub (pinned to 0c42157ee5)