{"record":{"id":"2527dea20808acf3","repo":"zeroclaw-labs/zeroclaw","slug":"at-least-one-topic-must-be-configured","errorCode":null,"errorMessage":"at least one topic must be configured","messagePattern":"at least one topic must be configured","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":16282,"sourceCode":"                \"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\n        if is_tls_scheme && !self.use_tls {\n            anyhow::bail!(\n                \"use_tls is false but broker_url uses 'mqtts://' (requires use_tls: true)\"\n            );\n        }\n\n        // Topics validation\n        if self.topics.is_empty() {\n            anyhow::bail!(\"at least one topic must be configured\");\n        }\n\n        // Client ID validation\n        if self.client_id.is_empty() {\n            validation_bail!(\n                RequiredFieldEmpty,\n                \"client_id\",\n                \"client_id must not be empty\"\n            );\n        }\n\n        Ok(())\n    }\n}\n\nimpl ChannelConfig for MqttConfig {\n    fn name() -> &'static str {\n        \"MQTT\"","sourceCodeStart":16264,"sourceCodeEnd":16300,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L16264-L16300","documentation":"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.","triggerScenarios":"A `[channels.mqtt.<alias>]` block with `enabled = true` and no `topics = [...]` key; `topics = []` written explicitly; topics removed while debugging and never restored.","commonSituations":"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).","solutions":["Add at least one MQTT topic filter, e.g. `topics = [\"sensors/#\"]`.","Use `#` (multi-level) or `+` (single-level) wildcards to broaden coverage instead of leaving the list empty.","Verify the filter matches the topics the SOP triggers expect."],"exampleFix":"# before\n[channels.mqtt.broker]\nbroker_url = \"mqtt://localhost:1883\"\nclient_id = \"zeroclaw\"\n# no topics\n\n# after\n[channels.mqtt.broker]\nbroker_url = \"mqtt://localhost:1883\"\nclient_id = \"zeroclaw\"\ntopics = [\"sensors/#\", \"alerts/+/critical\"]","handlingStrategy":"validation","validationCode":"anyhow::ensure!(\n    !cfg.topics.is_empty(),\n    \"channels.mqtt.{alias} needs at least one topic filter\"\n);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["MQTT delivers nothing without an explicit subscribe — an empty topic list is never useful.","Use `#` explicitly if you want all topics.","Validate configs in CI so an omitted key fails before deploy, not at runtime."],"tags":["mqtt","config","topics","required-field","zeroclaw"],"backgroundTag":"missing-required-config-field","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}