unicity-aos/aos-ce · warning

Dropped ingress message: connection bound to

Error message

Dropped ingress message: connection bound to {bound:?} but message claimed {claimed:?}

What it means

decide_ingress returned Drop with DropReason::PrincipalConflict: the message's claimed principal does not match the principal already bound to this connection. The library drops the message and returns an empty outcome, keeping the original binding intact — this prevents an authenticated connection from being hijacked by sending messages claiming a different identity.

Solutions

  1. Compare the logged {bound:?} vs {claimed:?} to see which identity mismatched and fix the client to send messages under its bound principal
  2. Have the client open a new connection instead of reusing one bound to a different principal
  3. If the principal legitimately changed, close and re-establish the connection so it rebinds
  4. Audit connection pooling/multiplexing code for socket sharing across identities

Example fix

// before
conn.send(msg_claiming(other_principal)) // conflicts with bound principal
// after
let conn = Connection::connect_as(my_principal)?;
conn.send(msg);
Defensive patterns

Strategy: validation

Validate before calling

if let Some(bound) = conn.bound_principal() {
    assert_eq!(bound, &msg.principal, "message principal must match bound connection principal");
}

Type guard

fn principal_matches(conn: &Connection, claimed: &Principal) -> bool {
    conn.bound_principal().map_or(false, |b| b == *claimed)
}

Prevention

When it happens

Trigger: A client reuses an already-bound connection and sends a message whose principal differs from the one bound at IngressDecision::Bind; decide_ingress returns Drop { reason: PrincipalConflict { bound, claimed } } and handle_ingress logs this warning.

Common situations: Connection pooling bugs where one client's socket is handed to another process; a client restarted with different credentials but kept the old socket; load balancers multiplexing sessions onto one connection; credentials rotated mid-session.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13). Data as JSON: /api/errors/ea8e0b245e6b9d14. Report an issue: GitHub.

Appendix: source

Thrown at capsules/capsule-cli/src/lib.rs:570

        Err(_) => {
            log::warn("Received malformed IPC payload from socket");
            return empty;
        }
    };

    let message_principal = msg.get("principal").and_then(|p| p.as_str());

    // Resolve the binding decision first — a conflicting or malformed
    // principal is dropped before any forward, and never mutates the binding.
    let (forward_as, newly_bound) = match decide_ingress(current_binding, message_principal) {
        IngressDecision::Bind(p) => (p.clone(), Some(p)),
        IngressDecision::ForwardAs(p) => (p, None),
        IngressDecision::Drop { reason } => {
            match reason {
                DropReason::InvalidPrincipal(p) => log::warn(format!(
                    "Dropped ingress message: malformed principal {p:?}; connection stays unbound"
                )),
                DropReason::PrincipalConflict { bound, claimed } => log::warn(format!(
                    "Dropped ingress message: connection bound to {bound:?} but message claimed {claimed:?}"
                )),
            }
            return empty;
        }
    };

    let (Some(topic), Some(payload)) = (
        msg.get("topic").and_then(|t| t.as_str()),
        msg.get("payload"),
    ) else {
        // No forwardable body, but the principal still binds the connection
        // (e.g. a bare handshake establishes identity for connect-tracking).
        // Nothing is forwarded, so the connection's session is never retargeted.
        log::warn("Ingress message has no topic/payload; binding only, nothing forwarded");
        return IngressOutcome {
            newly_bound,
            session_id: None,

View on GitHub (pinned to f6f22024fb)