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

  1. Regenerate each pin as base64(SHA256(DER of SubjectPublicKeyInfo)) and use the standard 'sha256/<base64>' form
  2. Validate the pin value independently (e.g. openssl x509 | derive SPKI digest) before adding it
  3. 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

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


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/b2a0fdd23f2bdc3a. Report an issue: GitHub.