nats-io/nats-server · error

bad service response type

Error message

bad service response type

What it means

ErrBadServiceType is returned when service latency tracking is being applied to a service whose response type is not Singleton. Latency tracking in nats-server only supports request-reply services with singleton responses; attaching it to a service export with a different response type (e.g. Stream/Chunked) is rejected.

Solutions

  1. Only enable latency tracking on services whose response type is Singleton
  2. Change the service export to Singleton if request-reply latency tracking is desired
  3. Remove the tracking call for non-singleton (streaming) services; latency sampling is unsupported for them
  4. Guard the call by checking the export's response type before enabling tracking

Example fix

// before
acc.AddServiceImport(other, "stream.svc", "")
acc.TrackServiceExportWithSampling("stream.svc", "results", 50) // streaming respType
// after
acc.AddServiceImport(other, "req.svc", "") // Singleton response
err := acc.TrackServiceExportWithSampling("req.svc", "results", 50)
Defensive patterns

Strategy: validation

Validate before calling

// confirm the export is Singleton before enabling latency tracking
if ea := acc.exports.services[svc]; ea == nil || ea.respType != Singleton {
	return fmt.Errorf("latency tracking requires Singleton response type for %q", svc)
}

Type guard

func isSingletonService(acc *Account, svc string) bool {
	acc.mu.RLock(); defer acc.mu.RUnlock()
	if acc.exports == nil || acc.exports.services == nil { return false }
	ea := acc.exports.services[svc]
	return ea != nil && ea.respType == Singleton
}

Try / catch

if err := acc.TrackServiceExportWithSampling(svc, resp, 100); err != nil {
	if errors.Is(err, ErrBadServiceType) { /* skip tracking for streaming services */ }
}

Prevention

When it happens

Trigger: Calling Account.TrackServiceExportWithSampling(service, respType, sampling) where the exported service's ea.respType is anything other than Singleton — e.g. a streaming response service — at server/accounts.go:1309.

Common situations: Developers enabling latency tracking on a service export that was configured for streaming/chunked responses; copy-pasting tracking setup between singleton and streaming services; upgrading code where a service changed response type but the tracking call was not updated.

Related errors


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

Appendix: source

Thrown at server/errors.go:117

	// ErrAccountExists is returned when an account is attempted to be registered
	// but already exists.
	ErrAccountExists = errors.New("account exists")

	// ErrBadAccount represents a malformed or incorrect account.
	ErrBadAccount = errors.New("bad account")

	// ErrReservedAccount represents a reserved account that can not be created.
	ErrReservedAccount = errors.New("reserved account")

	// ErrMissingAccount is returned when an account does not exist.
	ErrMissingAccount = errors.New("account missing")

	// ErrMissingService is returned when an account does not have an exported service.
	ErrMissingService = errors.New("service missing")

	// ErrBadServiceType is returned when latency tracking is being applied to non-singleton response types.
	ErrBadServiceType = errors.New("bad service response type")

	// ErrBadSampling is returned when the sampling for latency tracking is not 1 >= sample <= 100.
	ErrBadSampling = errors.New("bad sampling percentage, should be 1-100")

	// ErrAccountValidation is returned when an account has failed validation.
	ErrAccountValidation = errors.New("account validation failed")

	// ErrAccountExpired is returned when an account has expired.
	ErrAccountExpired = errors.New("account expired")

	// ErrNoAccountResolver is returned when we attempt an update but do not have an account resolver.
	ErrNoAccountResolver = errors.New("account resolver missing")

	// ErrAccountResolverUpdateTooSoon is returned when we attempt an update too soon to last request.
	ErrAccountResolverUpdateTooSoon = errors.New("account resolver update too soon")

	// ErrAccountResolverSameClaims is returned when same claims have been fetched.
	ErrAccountResolverSameClaims = errors.New("account resolver no new claims")

View on GitHub (pinned to 3a66a489d2)