nats-io/nats-server · error
websocket: %v
Error message
websocket: %v
What it means
Generic wrapper the websocket validator uses for TLS pinned-certificate failures: validatePinnedCerts rejected an entry in websocket.tls_pinned_certs and the raw validation error is wrapped with a "websocket: " prefix. The server fails startup.
Source
Thrown at server/websocket.go:1175
}
}
// Token/Username not possible if there are users/nkeys
if len(o.Users) > 0 || len(o.Nkeys) > 0 {
if wo.Username != _EMPTY_ {
return fmt.Errorf("websocket authentication username not compatible with presence of users/nkeys")
}
if wo.Token != _EMPTY_ {
return fmt.Errorf("websocket authentication token not compatible with presence of users/nkeys")
}
}
// Using JWT requires Trusted Keys
if wo.JWTCookie != _EMPTY_ {
if len(o.TrustedOperators) == 0 && len(o.TrustedKeys) == 0 {
return fmt.Errorf("trusted operators or trusted keys configuration is required for JWT authentication via cookie %q", wo.JWTCookie)
}
}
if err := validatePinnedCerts(wo.TLSPinnedCerts); err != nil {
return fmt.Errorf("websocket: %v", err)
}
// Check for invalid headers here.
for key := range wo.Headers {
k := strings.ToLower(key)
switch k {
case "host",
"content-length",
"connection",
"upgrade",
"nats-no-masking":
return fmt.Errorf("websocket: invalid header %q not allowed", key)
}
if strings.HasPrefix(k, "sec-websocket-") {
return fmt.Errorf("websocket: invalid header %q, \"Sec-WebSocket-\" prefix not allowed", key)
}
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Regenerate each pin as base64(SHA256(DER of SubjectPublicKeyInfo)) and use the standard 'sha256/<base64>' form
- Validate the pin value independently (e.g. openssl x509 | derive SPKI digest) before adding it
- Remove or fix the offending entry named in the wrapped error
Example fix
// before
websocket { tls_pinned_certs: ["abcdef"] }
// after
websocket { tls_pinned_certs: ["sha256/UC1o3S8GQyMWZaUOB4LE6HiuZNqSgIIfW1rNKghabH4="] } Defensive patterns
Strategy: validation
Validate before calling
for _, pin := range opts.Websocket.TLSPinnedCerts {
if !strings.HasPrefix(pin, "sha256/") {
return fmt.Errorf("bad pin %q: must be sha256/<base64>", pin)
}
if _, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(pin, "sha256/")); err != nil || len(mustDecode(pin)) != 32 {
return fmt.Errorf("bad pin %q", pin)
}
} Prevention
- Generate pins with a script (openssl SPKI digest + base64), never by hand
- Verify pins against the live cert chain before committing config
When it happens
Trigger: Configuring websocket { tls_pinned_certs: [...] } containing an invalid SPKI SHA-256 base64 hash, a cert format the validator doesn't recognize, or mixed/malformed entries.
Common situations: Hand-copying a pin with wrong base64 padding, using the full certificate hash instead of the SPKI hash, or typo'd prefix (must be like "sha256/...").
Related errors
- websocket requires TLS configuration
- leafnode: %v
- proxy is configured but remote URL %s requires TLS and no TL
- invalid chain link
- no available OCSP servers
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/b2a0fdd23f2bdc3a.
Report an issue: GitHub.