nats-io/nats-server · error · JSStreamInvalidConfigError
stream configuration invalid
Error message
stream configuration invalid
What it means
checkStreamCfgLocked rejects the whole stream config because it was nil. The JetStream API requires a non-nil StreamConfig to create or update a stream. This is the first guard in config validation and returns a JSStreamInvalidConfigError surfaced as API error 'stream configuration invalid'.
Source
Thrown at server/stream.go:1871
// StreamDefaultDuplicatesWindow default duplicates window.
const StreamDefaultDuplicatesWindow = 2 * time.Minute
// Do not hold the jetStream lock, it will be read-locked internally.
func (s *Server) checkStreamCfg(config *StreamConfig, acc *Account, pedantic bool) (StreamConfig, *ApiError) {
if js := s.getJetStream(); js != nil {
js.mu.RLock()
defer js.mu.RUnlock()
}
return s.checkStreamCfgLocked(config, acc, pedantic)
}
// jetStream lock (read or write) should be held, if JetStream is enabled.
func (s *Server) checkStreamCfgLocked(config *StreamConfig, acc *Account, pedantic bool) (StreamConfig, *ApiError) {
lim := &s.getOpts().JetStreamLimits
if config == nil {
return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("stream configuration invalid"))
}
if !isValidAssetName(config.Name) {
return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("stream name is required and can not contain '.', '*', '>', '\\', '/'"))
}
if len(config.Name) > JSMaxNameLen {
return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("stream name is too long, maximum allowed is %d", JSMaxNameLen))
}
if len(config.Description) > JSMaxDescriptionLen {
return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("stream description is too long, maximum allowed is %d", JSMaxDescriptionLen))
}
var metadataLen int
for k, v := range config.Metadata {
metadataLen += len(k) + len(v)
}
if metadataLen > JSMaxMetadataLen {
return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("stream metadata exceeds maximum size of %d bytes", JSMaxMetadataLen))
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Provide a complete StreamConfig in the request (at minimum Name, Subjects, Storage, Replicas).
- Check the JSON payload you send includes the 'config' key with an object.
- Use a maintained client (nats.go / jetstream package) that always serializes config.
- Log the request body when this occurs to confirm config is absent.
Example fix
// before
nc.Request(fmt.Sprintf(JSApiStreamCreateT, name), nil, time.Second)
// after
req := &jetstream.StreamConfig{Name: name, Subjects: []string{"foo"}, Storage: jetstream.FileStorage}
body, _ := json.Marshal(req)
nc.Request(fmt.Sprintf(JSApiStreamCreateT, name), body, time.Second) Defensive patterns
Strategy: validation
Validate before calling
func requireConfig(cfg *jetstream.StreamConfig) error {
if cfg == nil { return errors.New("stream config must not be nil") }
if cfg.Name == "" { return errors.New("stream name required") }
return nil
} Type guard
func hasStreamConfig(cfg *jetstream.StreamConfig) bool { return cfg != nil && cfg.Name != "" } Try / catch
cfg, err := js.GetStream(ctx, name)
if errors.Is(err, jetstream.ErrStreamNotFound) || cfg == nil {
// config was missing/invalid: build and resubmit a full StreamConfig
} Prevention
- Always construct StreamConfig via a single helper instead of ad-hoc literals.
- Never send nil/omitted config in raw JS API requests.
- Round-trip configs through json.Marshal in tests to catch missing fields.
- Use maintained client libraries instead of hand-crafted API requests.
- Log the outgoing request body when stream creation fails.
When it happens
Trigger: Issuing a JS API STREAM.CREATE or STREAM.UPDATE request whose 'config' field is missing or null; calling AddStream/Add/update with a nil *StreamConfig.
Common situations: Hand-crafted API request JSON omitting the config object; deserialization failure upstream leaving config nil; calling low-level server APIs directly instead of a client library.
Related errors
- JS_STREAM_MSG_DELETE_FAILED
- JS_STREAM_PURGE_FAILED
- JS_STREAM_ROLLUP_FAILED
- %w at offset %d
- stream republish transform from '%s' to '%s': %w
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/3bf1440ea6850f56.
Report an issue: GitHub.