Skip to content

Subjects and patterns

A subject is dot-separated tokens. a.b.c.

Token Matches
a literal itself, case sensitively
* exactly one token, in any position
> one or more tokens, and only as the final token

An empty token makes a subject invalid, and an invalid subject matches nothing.

func Match(pattern, subject string) bool
func ValidatePattern(pattern string) error   // may this be subscribed to
func ValidateSubject(subject string) error   // may this be published to

The rules are implemented, not approximated

Pattern Subject Match Why
a.* a.b.c no * is exactly one token, never a tail
* a.b no same
a.> a.b.c.d yes > is a tail
a.> a no the tail must match at least one token
> a.b.c yes a bare tail matches everything valid
a.*.c a..c no the empty token makes the subject invalid
a.B.c a.b.c no case sensitive

Those rows are from a truth table run three ways: against a real NATS server, against a matcher written from the documented rules, and against a prefix-and-glob approximation. The first two agreed on all 21 rows. The approximation disagreed on 6, in both directions.

So portability is real, and it is not free: it requires implementing the token rules rather than approximating them.

Validation refuses more than NATS does

Deliberately, and both cases it adds are silent failures.

Pattern What NATS does What this module does
a..b, a.b., .a.b, a b, "" refuses cleanly refuses
a.**, a.>> accepts refuses
a.>.c closes the connection refuses

a.** is accepted by NATS and can never match, because no token will ever equal **. That is a consumer receiving nothing for ever, with no error anywhere — the exact failure this module exists to eliminate.

a.>.c is not caught client-side at all. It reaches the server, which terminates the connection, so every other subscription on it dies too. One malformed pattern takes down the whole bus.

Validation is therefore this module's own guarantee rather than a backend feature being forwarded, which is why an invalid pattern is fatal at construction rather than degrading.

The limit

This pattern language is NATS-shaped. A backend with a flat namespace and no wildcard subscription, Kafka topics or SQS, cannot offer it. It reports Capabilities.Patterns: false, and a subscription that asks for a wildcard pattern there is refused at construction, fatally, rather than degraded: a pattern that silently matched only itself would be the exact silent failure this module exists to eliminate. Portable among backends that have a pattern language; not universal.