Checks/ACCOUNTS_005

NATS No Subscription Interest: What It Means and How to Fix It

Severity
Info
Category
Consistency
Applies to
Account
Check ID
ACCOUNTS_005
Detection threshold
active imports with no matching subscription interest in the importing account

No subscription interest means an account has an active import — a subject wired in from another account — but no client in the importing account subscribes to the imported subject. The import exists and is valid, but nothing is listening. Insights uses NATS wildcard subject matching to detect these, so a subscription on orders.us.> correctly satisfies interest on an import of orders.>.

Why this matters

NATS routes messages based on a subscription interest graph. When Account A exports a subject and Account B imports it, the server expects Account B to have subscribers on that subject. If no subscribers exist, the import is dead weight. In isolation, this is harmless — no messages flow, no resources are wasted on delivery. But it’s a strong signal that something is misconfigured, and in multi-tenant environments with dozens or hundreds of accounts, these dead imports accumulate into a configuration maintenance burden that obscures real problems.

The more common and more dangerous scenario is when the import was supposed to have subscribers. A service that should be consuming cross-account data isn’t subscribed — maybe it crashed, maybe it deployed with a wrong subject string, maybe the import uses a local_subject remapping that doesn’t match what the application subscribes to. In these cases, the “no subscription interest” finding is the first signal that a data pipeline is silently broken. No errors are thrown, no connections fail — the messages simply go nowhere.

In operator-managed environments with account JWTs, dead imports also make configuration audits harder. When reviewing an account’s import list, every import should map to a real consumer. Unused imports raise questions: Is this intentional? Is a service down? Can we remove this safely? Cleaning up dead imports reduces the surface area for confusion and makes the import/export topology easier to reason about.

Common causes

  • Application not yet deployed. The account JWT was provisioned with imports before the consuming application was deployed. The import is valid but no client has connected to use it yet. Common during staged rollouts where infrastructure configuration leads application deployment.

  • Incorrect subject or local_subject mapping. The import maps the remote subject to a local_subject, but the subscribing application uses the original subject name — or vice versa. The subscription exists but doesn’t match the imported subject after remapping, so the server sees no interest.

  • Subscriber crashed or was decommissioned. A service that previously consumed the imported subject is no longer running. The import remains in the account JWT, but no client subscribes to it. This is the most operationally significant cause because it represents a broken data flow.

  • Wildcard mismatch between import and subscription. The import covers orders.> but the subscriber subscribes to orders.us.>. NATS checks for interest using wildcard matching — a subscription on orders.us.> does satisfy interest on orders.>. But if the import is orders.us.created and the subscription is orders.>, that also matches. Mismatches happen when the import subject is very specific and the subscriber uses a different token structure.

  • Publisher-only account with unnecessary imports. The account was configured with both imports and exports, but in practice it only publishes. The imports were added “just in case” and never used.

How to diagnose

List active imports for the account

Use the nats CLI to inspect the account’s import configuration:

Terminal window
nats server account info <account_name>

This shows the account’s imports, exports, connections, and subscription counts. Look for imports where the subject has no corresponding subscription.

Check per-connection subscriptions

Inspect what subjects each connection in the account is subscribed to:

Terminal window
nats server report connections --account <account_name> --sort subs

For more detail, use the monitoring endpoint:

Terminal window
curl -s "http://localhost:8222/connz?acc=<account_name>&subs=true" | jq '.connections[] | {name, subs}'

This shows every subscription for every connection in the account. Compare this list against the imported subjects. If no subscription matches the imported subject (including wildcard overlap), that import has no interest.

Verify the import is active

An import can be both inactive (ACCOUNTS_003) and lacking interest (ACCOUNTS_005) for different reasons. Confirm the import is active first:

Terminal window
curl -s "http://localhost:8222/accstatz" | jq '.account_statz[] | select(.acc == "<account_name>")'

If the import appears in the active imports list but has no matching subscription, you have a confirmed no-interest finding.

Check if the subscribing application is running

If a specific service should be consuming the imported subject:

Terminal window
# List connections with their client name
nats server report connections --account <account_name>

If the expected client name doesn’t appear in the connection list, the application is likely not running.

How to fix it

Immediate: verify whether the import is needed

Before removing anything, determine if the import should have subscribers:

Terminal window
# Check if any service should be consuming this import
nats server account info <account_name>

If the import was intentional and a service should be subscribing, restart or redeploy the consuming application. If the import is genuinely unused, proceed to removal.

Short-term: fix subscriber configuration or clean up stale imports

If the subscriber exists but uses the wrong subject, correct the application’s subscription to match the imported subject (or its local_subject remapping):

1
// Go — subscribe to the correct local_subject
2
nc, err := nats.Connect(url, nats.UserCredentials("account_b.creds"))
3
if err != nil {
4
log.Fatal(err)
5
}
6
7
// If the import maps "orders.>" to local_subject "imported.orders.>"
8
// subscribe to the local_subject, not the original
9
_, err = nc.Subscribe("imported.orders.>", func(msg *nats.Msg) {
10
log.Printf("Received: %s", string(msg.Data))
11
})
1
# Python — subscribe to the correct local_subject
2
import nats
3
4
async def main():
5
nc = await nats.connect("nats://localhost:4222", user_credentials="account_b.creds")
6
7
# Match the local_subject defined in the import
8
async def handler(msg):
9
print(f"Received: {msg.data.decode()}")
10
11
await nc.subscribe("imported.orders.>", cb=handler)

If the import is no longer needed, remove it from the account JWT:

Terminal window
# Edit the account JWT to remove the unused import
nsc delete import --account <account_name> --subject "orders.>"
# Push the updated JWT
nsc push -a <account_name>

Long-term: audit import/export topology regularly

Establish a practice of reviewing account imports as part of deployment lifecycle. When decommissioning a service, remove its corresponding imports. Use Synadia Insights to automatically flag accounts with dead imports so they don’t accumulate.

Pair this check with ACCOUNTS_004 (Orphaned Export) for a complete view: ACCOUNTS_005 finds imports with no consumers, and ACCOUNTS_004 finds exports with no importers. Together, they surface the full set of dead cross-account wiring.

Frequently asked questions

Is it a problem if an import has no subscription interest?

Not always. Publisher-only accounts may legitimately have no subscriptions on imported subjects if the import is a service type (request-reply) and the account only sends requests through it. However, for stream-type imports where the account should be receiving a flow of messages, no subscription interest means those messages are going nowhere. This check surfaces the finding so you can determine which case applies.

How does NATS match subscriptions against imports?

NATS uses its standard wildcard matching. An import on orders.> is satisfied by a subscription on orders.us.created, orders.>, or orders.*. The check uses the same matching logic — it only fires when literally no subscription in the account overlaps with the imported subject. If you have even one subscription that matches via wildcards, the check passes.

What’s the difference between this check and Inactive JWT Import (ACCOUNTS_003)?

ACCOUNTS_003 flags imports that aren’t activated by the server at all — the activation token is expired, missing, or signed by a rotated key. ACCOUNTS_005 flags imports that are active and valid but have no subscriber consuming them. An import can pass ACCOUNTS_003 (it’s active) but fail ACCOUNTS_005 (nobody’s listening). They diagnose different problems: one is configuration validity, the other is operational usage.

Should I remove all imports with no subscription interest?

Not without investigation. Some imports may be for services that are temporarily offline, or for disaster recovery consumers that only activate during failover. Review each flagged import against your intended architecture before removing it. The safe path is to verify with the team that owns the subscribing service, then remove if confirmed unused.

Proactive monitoring for NATS no subscription interest with Synadia Insights

With 100+ always-on audit Checks from the NATS experts, Insights helps you find and fix problems before they become costly incidents.
No alert rules to write. No dashboards to maintain.

Start a 14-day Insights trial
Cancel