Troubleshooting
Common issues and how to resolve them.
Always disconnect your client
You should always manually disconnect your client with client.disconnect().await. The client writes to a local DB and manages SURB storage, so it needs to shut down gracefully. Failing to do this can lead to the errors described below.
Waiting for non-empty messages
When listening for a response, you may receive empty messages. These are SURB replenishment requests: the remote side asking for more reply SURBs. Filter them out:
let mut message = None;
while let Some(new_message) = client.wait_for_messages().await {
if !new_message.is_empty() {
message = new_message.into_iter().next();
break;
}
}Prefer client.next().await (from the futures::StreamExt trait, not the Nym Stream module) over client.wait_for_messages().await; it returns one message at a time which is easier to work with. You'll need use futures::StreamExt; in scope.
Verbose task client is being dropped logging
On client shutdown (expected)
When calling client.disconnect().await, the client logs that its background tasks are shutting down. This is normal and expected.
Control log verbosity with RUST_LOG:
RUST_LOG=warn cargo run --example simpleNot on client shutdown (unexpected)
If you see these messages unexpectedly, you may be killing the client process too early. See the next section.
Accidentally killing your client process too early
If you see errors like Polling shutdown failed: channel closed or panics about action control task has died, your client is being dropped before it finishes sending.
send_plain_message() is async, but it only blocks until the message is placed in the client's internal queue, not until it's actually sent into the Mixnet. After queuing, the client still needs to route-encrypt the message and interleave it with cover traffic.
Make sure the program stays alive long enough. In practice this means awaiting a response or calling sleep before disconnecting:
// Send a message
client.send_plain_message(recipient, "hello").await.unwrap();
// Wait for the reply (keeps the client alive)
if let Some(received) = client.wait_for_messages().await {
for r in received {
println!("Received: {}", String::from_utf8_lossy(&r.message));
}
}
// Always disconnect gracefully
client.disconnect().await;Lots of duplicate fragment received messages
WARN level logs about duplicate fragments are caused by Mixnet-level packet retransmission: the original and the retransmitted copy both arrive. This is not a bug in your client logic.