zeroclaw-labs/zeroclaw · error
qos must be 0, 1, or 2, got {}
Error message
qos must be 0, 1, or 2, got {} What it means
MQTT defines exactly three QoS levels: 0 (at-most-once), 1 (at-least-once), 2 (exactly-once). `MqttConfig::qos` is a `u8` with serde default 1, so the validator must reject any value above 2 before the channel connects, since the underlying MQTT client cannot map 3–255 to a protocol level.
Source
Thrown at crates/zeroclaw-config/src/schema.rs:16255
/// are not exposed to the model when responding via this channel.
#[tab(Behavior)]
#[serde(default)]
pub excluded_tools: Vec<String>,
}
impl MqttConfig {
/// Validate the MQTT configuration.
///
/// Checks:
/// - QoS is 0, 1, or 2
/// - broker_url uses valid scheme (`mqtt://` or `mqtts://`)
/// - `use_tls` flag matches broker_url scheme
/// - At least one topic is configured
/// - client_id is non-empty
pub fn validate(&self) -> anyhow::Result<()> {
// QoS validation
if self.qos > 2 {
anyhow::bail!("qos must be 0, 1, or 2, got {}", self.qos);
}
// Broker URL validation
let is_tls_scheme = self.broker_url.starts_with("mqtts://");
let is_mqtt_scheme = self.broker_url.starts_with("mqtt://");
if !is_tls_scheme && !is_mqtt_scheme {
anyhow::bail!(
"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://')");
}
View on GitHub (pinned to 88bb9c8533)
Solutions
- Set qos to 0, 1, or 2 — 1 (the default) is correct for most SOP listeners.
- If you need exactly-once-style semantics for critical alerts, use 2 knowingly (it adds handshake overhead).
- If the value came from code, clamp or validate the source before writing config.
Example fix
# before [channels.mqtt.broker] qos = 3 # after [channels.mqtt.broker] qos = 1
Defensive patterns
Strategy: validation
Validate before calling
fn valid_qos(qos: u8) -> bool { qos <= 2 }
// before building/loading config:
anyhow::ensure!(valid_qos(cfg.qos), "qos {} out of range", cfg.qos); Type guard
fn valid_qos(qos: u8) -> bool { qos <= 2 } Prevention
- Remember MQTT has exactly three levels: 0, 1, 2 — there is no 3.
- Default (1) is almost always right; change it only with the broker's semantics in mind.
- Never derive qos from unvalidated numeric input.
When it happens
Trigger: `qos = 3` (or any 3–255 value) in a `[channels.mqtt.<alias>]` block; computing qos programmatically and passing an out-of-range u8; deserializing config from JSON where qos was stored as a larger integer.
Common situations: Assuming higher QoS numbers mean 'more reliable' and inventing 3; porting configs from systems with unrelated numeric delivery guarantees; typos (e.g. 11 for 1).
Related errors
- broker_url must start with 'mqtt://' or 'mqtts://', got: {}
- use_tls is true but broker_url uses 'mqtt://' (not 'mqtts://
- use_tls is false but broker_url uses 'mqtts://' (requires us
- at least one topic must be configured
- {entry_path}.tool must be a non-empty exact tool name withou
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/bde1d74cdcf9b51d.
Report an issue: GitHub.