NATS '>' wildcard case sensitivity across '/'-delimited subjects
0 reputation · 07 Jan 2021, 22:04 UTC
0 reputation · 07 Jan 2021, 22:04 UTC
NATS subject-based routing uses '*' and ' wildcards to filter messages across /-delimited subject trees. The '>' wildcard matches any number of tokens after its position, and the specification states that matching is case‑sensitive (e.g., com.> does not match COM.>).
In bridged or multi‑tenant deployments, operators sometimes report that '>' subscriptions deliver messages whose subject tokens differ in case, suggesting a possible deviation from the documented behavior. This uncertainty affects access‑control policies, subject quotas, and bridge subject mapping designs.
The goal is to pinpoint the exact matching boundary for '>' wildcards when subject tokens vary in case and to determine whether server version, JetStream configuration, or bridge hops influence the outcome.
Does '>' matching enforce case sensitivity uniformly across NATS server versions and bridge hops? Is there a server‑level configuration to normalize subject case for wildcard evaluation? How do JetStream streams interact with case‑variant wildcard subscriptions?
35275 reputation · 08 Jan 2021, 09:23 UTC
Yes — > matching is case-sensitive, and it is case-sensitive uniformly: across server versions, across gateway/leaf/bridge hops, and inside JetStream. There is no server-level option to normalize subject case. But the premise in your question contains a more important correction: NATS subjects are dot-delimited, not slash-delimited. If your deployment is routing on /-separated subjects, the surprising behavior you are seeing almost certainly comes from that mismatch, not from case handling.
. only. a/b is a single token containing a literal slash, not two hierarchy levels.orders.US and orders.us are distinct subjects; a subscription on one never receives messages published to the other.> matches one or more trailing tokens and must be the final token of the subscription. orders.> matches orders.us and orders.us.ny, but not orders alone, and not orders.US.* matches exactly one token at its position, with the same exact, case-sensitive comparison.When operators observe a > subscription receiving subjects that "differ in case," the usual causes are:
Orders/US/East and a subscriber on Orders.> — the subscriber receives nothing, because Orders/US/East is one token and the subscription expects a dot after Orders. Conversely, a subscription on the literal subject Orders/US/East matches only that exact string. Teams migrating from MQTT or path-based systems hit this constantly and misread it as a wildcard or case bug.foo.> and a literal case-variant subscription can make it look like one wildcard matched both cases.JetStream streams capture messages whose subjects match the stream's configured subjects using the same token rules — case-sensitive, dot-delimited. A stream configured with orders.> will not store messages published to Orders.us. There is no JetStream setting that changes this, and no nats-server configuration flag for case-insensitive subject matching in any released version. This behavior has been stable across the 2.x line; if you are on an unusual fork or a very old 1.x server, verify directly rather than assuming.
# Terminal 1: case-variant wildcard subscriber
nats sub 'foo.>'
# Terminal 2: publish with different case — expect NO delivery
nats pub Foo.Bar "should not arrive"
nats pub foo.bar "should arrive"
# Slash test: this is one token, not a hierarchy
nats sub 'a.>' # receives nothing from the publish below
nats pub 'a/b' "literal slash token"
nats sub 'a/b' # this one DOES receive itIf your bridged deployment shows deliveries that contradict this, capture the subject as seen on each hop (nats sub with headers, or trace via monitoring endpoints) to find where a mapping is rewriting it.
Pick one casing convention (lowercase is the common choice), enforce it at publisher boundaries, and convert any slash-delimited subjects to dots before they enter NATS. Case-sensitivity is a feature for access control here: permissions on tenant-a.> cannot be bypassed by publishing to Tenant-A.x, because that is simply a different subject tree.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 07 Jan 2021, 23:14 UTC
To build on the previous point regarding tokenization, it is critical to verify how the > wildcard interacts with case sensitivity when the initial token matches but subsequent tokens vary. Because NATS performs an exact byte-for-byte comparison of each token, the case sensitivity is evaluated independently for every segment of the subject.
If you are troubleshooting unexpected delivery or missing messages, you can verify this behavior using the NATS CLI with the following test cases:
orders.>orders.USA: Delivered (Initial token matches case).Orders.USA: Not delivered (Initial token case mismatch).orders.usa: Delivered (Initial token matches; > ignores case of subsequent tokens because it matches any token).This confirms that while the > wildcard is "case-insensitive" in the sense that it accepts any token regardless of case, the prefix leading up to the wildcard must match exactly. If the reported case-variant deliveries occur on the prefix, it suggests an external middleware or proxy is normalizing subjects before they reach the NATS server.