{"record":{"id":"bde1d74cdcf9b51d","repo":"zeroclaw-labs/zeroclaw","slug":"qos-must-be-0-1-or-2-got","errorCode":null,"errorMessage":"qos must be 0, 1, or 2, got {}","messagePattern":"qos must be 0, 1, or 2, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":16255,"sourceCode":"    /// are not exposed to the model when responding via this channel.\n    #[tab(Behavior)]\n    #[serde(default)]\n    pub excluded_tools: Vec<String>,\n}\n\nimpl MqttConfig {\n    /// Validate the MQTT configuration.\n    ///\n    /// Checks:\n    /// - QoS is 0, 1, or 2\n    /// - broker_url uses valid scheme (`mqtt://` or `mqtts://`)\n    /// - `use_tls` flag matches broker_url scheme\n    /// - At least one topic is configured\n    /// - client_id is non-empty\n    pub fn validate(&self) -> anyhow::Result<()> {\n        // QoS validation\n        if self.qos > 2 {\n            anyhow::bail!(\"qos must be 0, 1, or 2, got {}\", self.qos);\n        }\n\n        // Broker URL validation\n        let is_tls_scheme = self.broker_url.starts_with(\"mqtts://\");\n        let is_mqtt_scheme = self.broker_url.starts_with(\"mqtt://\");\n\n        if !is_tls_scheme && !is_mqtt_scheme {\n            anyhow::bail!(\n                \"broker_url must start with 'mqtt://' or 'mqtts://', got: {}\",\n                self.broker_url\n            );\n        }\n\n        // TLS flag validation\n        if is_mqtt_scheme && self.use_tls {\n            anyhow::bail!(\"use_tls is true but broker_url uses 'mqtt://' (not 'mqtts://')\");\n        }\n","sourceCodeStart":16237,"sourceCodeEnd":16273,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L16237-L16273","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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).","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."],"exampleFix":"# before\n[channels.mqtt.broker]\nqos = 3\n\n# after\n[channels.mqtt.broker]\nqos = 1","handlingStrategy":"validation","validationCode":"fn valid_qos(qos: u8) -> bool { qos <= 2 }\n// before building/loading config:\nanyhow::ensure!(valid_qos(cfg.qos), \"qos {} out of range\", cfg.qos);","typeGuard":"fn valid_qos(qos: u8) -> bool { qos <= 2 }","tryCatchPattern":null,"preventionTips":["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."],"tags":["mqtt","config","qos","zeroclaw"],"backgroundTag":"mqtt-invalid-qos","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}