nats-io/nats-server · error · JSStreamInvalidConfigError
10052
10052
Error message
stream configuration for create can not be sealed
What it means
Sealed is a terminal stream state: once sealed, a stream is immutable and can never accept new data or configuration. Creating a new stream with Sealed already set in the configuration is contradictory, so the JetStream API rejects it with JSStreamInvalidConfigError (API error code 10052) rather than creating a permanently write-blocked stream.
Source
Thrown at server/jetstream_api.go:1515
setStaticStreamMetadata(&cfg.StreamConfig)
streamName := streamNameFromSubject(subject)
if streamName != cfg.Name {
resp.Error = NewJSStreamMismatchError()
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
// Check for path like separators in the name.
if strings.ContainsAny(streamName, `\/`) {
resp.Error = NewJSStreamNameContainsPathSeparatorsError()
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
// Can't create a stream with a sealed state.
if cfg.Sealed {
resp.Error = NewJSStreamInvalidConfigError(fmt.Errorf("stream configuration for create can not be sealed"))
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
// If we are told to do mirror direct but are not mirroring, error.
if cfg.MirrorDirect && cfg.Mirror == nil {
resp.Error = NewJSStreamInvalidConfigError(fmt.Errorf("stream has no mirror but does have mirror direct"))
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
return
}
// Hand off to cluster for processing.
if s.JetStreamIsClustered() {
s.jsClusteredStreamRequest(ci, acc, subject, reply, rmsg, &cfg)
return
}
if err := acc.jsNonClusteredStreamLimitsCheck(&cfg.StreamConfig); err != nil {View on GitHub (pinned to 3a66a489d2)
Solutions
- Remove `sealed: true` from the create request config; seal the stream later with an update after creation.
- If cloning an existing sealed stream, strip the Sealed field before serializing the config.
- Use the stream restore API ($JS.API.STREAM.RESTORE) rather than create when reconstructing archived streams.
Example fix
// before
json.Marshal(&StreamConfig{Name: "x", Sealed: true}) // create rejected
// after
json.Marshal(&StreamConfig{Name: "x"}) // create, then seal via update if needed Defensive patterns
Strategy: validation
Validate before calling
if cfg.Sealed {
return errors.New("cannot create a stream with sealed=true; seal after creation via update")
} Try / catch
// handle API error code 10052
if jserr != nil && jserr.ErrorCode == 10052 {
// strip Sealed from config and retry create
} Prevention
- Strip the Sealed field when cloning or restoring stream configs.
- Seal streams with an update request after creation, never at create time.
- Use STREAM.RESTORE for replaying archived stream state.
When it happens
Trigger: Sending STREAM CREATE ($JS.API.STREAM.CREATE.<name>) with a config JSON where "sealed": true.
Common situations: Restoring/backing up scripts that dump full stream state (including sealed) and replay it as a create request; template code that serializes a sealed source stream's config to clone it.
Related errors
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/f4b24c919dfc4966.
Report an issue: GitHub.