zeroclaw-labs/zeroclaw · error

at least one topic must be configured

Error message

at least one topic must be configured

What it means

An MQTT channel subscribes to a list of topic filters (e.g. `sensors/#`, `alerts/+/critical`). A channel with zero topics would connect and receive nothing, so `MqttConfig::validate` requires at least one entry; `topics` has a serde default of an empty vec, which means an omitted key fails validation rather than silently doing nothing.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:16282

                "broker_url must start with 'mqtt://' or 'mqtts://', got: {}",
                self.broker_url
            );
        }

        // TLS flag validation
        if is_mqtt_scheme && self.use_tls {
            anyhow::bail!("use_tls is true but broker_url uses 'mqtt://' (not 'mqtts://')");
        }

        if is_tls_scheme && !self.use_tls {
            anyhow::bail!(
                "use_tls is false but broker_url uses 'mqtts://' (requires use_tls: true)"
            );
        }

        // Topics validation
        if self.topics.is_empty() {
            anyhow::bail!("at least one topic must be configured");
        }

        // Client ID validation
        if self.client_id.is_empty() {
            validation_bail!(
                RequiredFieldEmpty,
                "client_id",
                "client_id must not be empty"
            );
        }

        Ok(())
    }
}

impl ChannelConfig for MqttConfig {
    fn name() -> &'static str {
        "MQTT"

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Add at least one MQTT topic filter, e.g. `topics = ["sensors/#"]`.
  2. Use `#` (multi-level) or `+` (single-level) wildcards to broaden coverage instead of leaving the list empty.
  3. Verify the filter matches the topics the SOP triggers expect.

Example fix

# before
[channels.mqtt.broker]
broker_url = "mqtt://localhost:1883"
client_id = "zeroclaw"
# no topics

# after
[channels.mqtt.broker]
broker_url = "mqtt://localhost:1883"
client_id = "zeroclaw"
topics = ["sensors/#", "alerts/+/critical"]
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(
    !cfg.topics.is_empty(),
    "channels.mqtt.{alias} needs at least one topic filter"
);

Prevention

When it happens

Trigger: A `[channels.mqtt.<alias>]` block with `enabled = true` and no `topics = [...]` key; `topics = []` written explicitly; topics removed while debugging and never restored.

Common situations: Enabling the channel before deciding the topic layout; templating configs where the topics array is conditionally empty; believing the broker will push everything without a subscription (MQTT requires an explicit subscribe).

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/2527dea20808acf3. Report an issue: GitHub.