{"record":{"id":"bc83d3b4327a0226","repo":"unicity-aos/aos-ce","slug":"ingress-message-has-no-topic-payload-binding-only-nothing","errorCode":null,"errorMessage":"Ingress message has no topic/payload; binding only, nothing forwarded","messagePattern":"Ingress message has no topic/payload; binding only, nothing forwarded","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"capsules/capsule-cli/src/lib.rs","lineNumber":585,"sourceCode":"                DropReason::InvalidPrincipal(p) => log::warn(format!(\n                    \"Dropped ingress message: malformed principal {p:?}; connection stays unbound\"\n                )),\n                DropReason::PrincipalConflict { bound, claimed } => log::warn(format!(\n                    \"Dropped ingress message: connection bound to {bound:?} but message claimed {claimed:?}\"\n                )),\n            }\n            return empty;\n        }\n    };\n\n    let (Some(topic), Some(payload)) = (\n        msg.get(\"topic\").and_then(|t| t.as_str()),\n        msg.get(\"payload\"),\n    ) else {\n        // No forwardable body, but the principal still binds the connection\n        // (e.g. a bare handshake establishes identity for connect-tracking).\n        // Nothing is forwarded, so the connection's session is never retargeted.\n        log::warn(\"Ingress message has no topic/payload; binding only, nothing forwarded\");\n        return IngressOutcome {\n            newly_bound,\n            session_id: None,\n        };\n    };\n\n    if !is_allowed_ingress_topic(topic) {\n        // A blocked-topic message is neither forwarded nor allowed to retarget\n        // the connection's session — otherwise a client could spoof itself onto\n        // another session's stream with an unforwarded message.\n        log::warn(format!(\"Dropped ingress message to blocked topic: {topic}\"));\n        return IngressOutcome {\n            newly_bound,\n            session_id: None,\n        };\n    }\n\n    // Always forward under the connection's bound principal. There is no","sourceCodeStart":567,"sourceCodeEnd":603,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/capsules/capsule-cli/src/lib.rs#L567-L603","documentation":"An ingress message carried a principal (so it could bind the connection) but had no topic/payload body to forward. The library logs a warning, keeps the binding (newly_bound is preserved), and returns IngressOutcome { newly_bound, session_id: None } — nothing is forwarded and no session is retargeted. This supports bare handshake messages that exist only to establish identity for connect-tracking.","triggerScenarios":"A client sends a message with a valid principal but the let-else `msg.get(\"topic\")...else` fails because the \"topic\" is not a string or \"payload\" is missing; handle_ingress logs this warning and returns without forwarding.","commonSituations":"Handshake-only clients that connect just to register identity; clients with a serialization bug dropping the topic field; JSON where topic is a non-string value (number/null) so t.as_str() returns None.","solutions":["If this is an intentional bare handshake, ignore the warning or downgrade it in the client protocol docs","Ensure the client always sends a string \"topic\" and a \"payload\" when it expects forwarding","Validate message shape client-side before sending (topic: string, payload: present)","Check for serialization bugs where the topic/payload fields are omitted or mistyped"],"exampleFix":"// before\n{\"principal\": p} // binding only, nothing forwarded\n// after\n{\"principal\": p, \"topic\": \"events\", \"payload\": {...}}","handlingStrategy":"validation","validationCode":"fn forwardable(msg: &serde_json::Value) -> bool {\n    msg.get(\"topic\").and_then(|t| t.as_str()).is_some()\n        && msg.get(\"payload\").map_or(false, |p| !p.is_null())\n}","typeGuard":"fn extract_topic(msg: &serde_json::Value) -> Option<&str> {\n    msg.get(\"topic\").and_then(|t| t.as_str())\n}","tryCatchPattern":null,"preventionTips":["Include a string topic and payload in every message intended for forwarding","Distinguish intentional handshake-only messages from accidentally empty ones","Schema-validate ingress JSON before sending (topic: string required)","Keep client serialization in sync with the proxy's expected message shape"],"tags":["ingress","handshake","payload"],"backgroundTag":"empty-required-field","analyzedSha":"f6f22024fb1e8d122f28a1b4a9f75aee448ae839","analyzedAt":"2026-09-13T03:04:44.565Z","contentChangedAt":"2026-09-13T03:04:44.565Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}