stalwartlabs/stalwart · error

Cluster::SubscriberError

Error message

Cluster::SubscriberError

What it means

The NATS backend raises Cluster::SubscriberError when `client.subscribe(topic)` fails while setting up a subscription for the given subject. The failure is converted into a trc::Error with the async-nats error attached as the reason.

Source

Thrown at crates/coordinator/src/backend/nats/pubsub.rs:30

pub struct NatsPubSubStream {
    subs: async_nats::Subscriber,
}

impl NatsPubSub {
    pub async fn publish(&self, topic: &'static str, message: Vec<u8>) -> trc::Result<()> {
        self.client
            .publish(topic, message.into())
            .await
            .map_err(|err| Error::new(EventType::Cluster(ClusterEvent::PublisherError)).reason(err))
    }

    pub async fn subscribe(&self, topic: &'static str) -> trc::Result<PubSubStream> {
        self.client
            .subscribe(topic)
            .await
            .map(|subs| PubSubStream::Nats(NatsPubSubStream { subs }))
            .map_err(|err| {
                Error::new(EventType::Cluster(ClusterEvent::SubscriberError)).reason(err)
            })
    }
}

impl NatsPubSubStream {
    pub async fn next(&mut self) -> Option<Msg> {
        self.subs.next().await.map(Msg::Nats)
    }
}

View on GitHub (pinned to e962003857)

Solutions

  1. Check the attached reason for the exact async-nats subscribe error.
  2. Ensure the subject is valid NATS syntax: dot-separated tokens, no spaces, allowed wildcards ('*', '>') only in subscribe subjects.
  3. Confirm the NATS connection is alive before subscribing (await connect result / flush).
  4. Retry subscribe after reconnecting if the server was temporarily unreachable.

Example fix

// before
let subs = nats.subscribe("a b.c").await?; // space invalid
// after
let subs = nats.subscribe("events.cluster").await?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_nats_subject(s: &str) -> bool {
    !s.is_empty()
        && !s.starts_with('.')
        && !s.ends_with('.')
        && !s.contains(' ')
        && s.split('.').all(|tok| !tok.is_empty())
}

Try / catch

match nats.subscribe(subject).await {
    Ok(subs) => /* use subs */,
    Err(e) => {
        tracing::error!(subject, reason = ?e.reason(), "nats subscribe failed");
        // fall back to resubscribe loop after reconnect
    }
}

Prevention

When it happens

Trigger: Calling `NatsPubSub::subscribe(topic)` when async-nats returns an error from subscribe: invalid subject name, or the subscription request could not be sent because the connection is down.

Common situations: Malformed subject (empty string, spaces, leading/trailing dots); publishing/subscribing before the connection is established; NATS server unavailable.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06). Data as JSON: /api/errors/57b12bc87730456e. Report an issue: GitHub.