nats-io/nats-server · error
OnReload, sort or explicitly skip type: %s
Error message
OnReload, sort or explicitly skip type: %s
What it means
applyOptions/diff machinery switches over every option type changed during reload; the default branch rejects types that were not sorted (mapped to a diff option) or explicitly skipped. This is a developer-facing guard so newly added config fields must be handled in the reload diff switch.
Source
Thrown at server/reload.go:1574
case []*url.URL:
slices.SortFunc(value, func(i, j *url.URL) int { return cmp.Compare(i.String(), j.String()) })
case []string:
slices.Sort(value)
case []*jwt.OperatorClaims:
slices.SortFunc(value, func(i, j *jwt.OperatorClaims) int { return cmp.Compare(i.Issuer, j.Issuer) })
case GatewayOpts:
slices.SortFunc(value.Gateways, func(i, j *RemoteGatewayOpts) int { return cmp.Compare(i.Name, j.Name) })
case WebsocketOpts:
slices.Sort(value.AllowedOrigins)
case string, bool, uint8, uint16, uint64, int, int32, int64, time.Duration, float64, nil, LeafNodeOpts, ClusterOpts, *tls.Config, PinnedCertSet,
*URLAccResolver, *MemAccResolver, *DirAccResolver, *CacheDirAccResolver, Authentication, MQTTOpts, jwt.TagList,
*OCSPConfig, map[string]string, map[string]bool, JSLimitOpts, StoreCipher, *OCSPResponseCacheConfig, *ProxiesConfig, WriteTimeoutPolicy:
// explicitly skipped types
case *AuthCallout:
case JSTpmOpts:
default:
// this will fail during unit tests
return fmt.Errorf("OnReload, sort or explicitly skip type: %s",
reflect.TypeOf(value))
}
return nil
}
// diffOptions returns a slice containing options which have been changed. If
// an option that doesn't support hot-swapping is changed, this returns an
// error.
func (s *Server) diffOptions(newOpts *Options) ([]option, error) {
var (
oldOpts = s.getOpts()
oldConfig = reflect.ValueOf(oldOpts).Elem()
newConfig = reflect.ValueOf(newOpts).Elem()
diffOpts = []option{}
skipTKeys = len(oldOpts.TrustedOperators) > 0 && len(oldOpts.TrustedKeys) > 0
// Need to keep track of whether JS is being disabled
// to prevent changing limits at runtime.View on GitHub (pinned to 3a66a489d2)
Solutions
- Add a case for the missing type in the reload diff switch in server/reload.go, mapping it to an appropriate option.
- Add the type to the explicitly-skipped case list if the field does not support hot reload.
- Restart the server instead of reloading if you cannot modify the code handling the new option type.
Example fix
// before
default:
return fmt.Errorf("OnReload, sort or explicitly skip type: %s", reflect.TypeOf(value))
// after
case *MyNewOptionType:
diffOpts = append(diffOpts, &myNewOption{newValue: value.(*MyNewOptionType)}) Defensive patterns
Strategy: fallback
Try / catch
if err := srv.Reload(); err != nil {
if strings.Contains(err.Error(), "OnReload, sort or explicitly skip type") {
log.Fatalf("new option type not handled for reload: %v", err) // fall back to restart
}
} Prevention
- When adding Options fields, always update the reload type switch in server/reload.go.
- Run the reload unit tests (the switch is designed to fail there) in CI.
- Explicitly skip types that must not support hot reload.
When it happens
Trigger: A new options field's type (e.g. a custom struct) is changed at runtime and passed to the reload diff switch without a case or an explicit skip entry, causing this error during Reload().
Common situations: Contributors adding a new config option to server Options without updating server/reload.go's type switch; custom forks with extended Options fields being hot-reloaded.
Related errors
- field "Users": old=%v, new=%v
- remote %s: %s
- remote %s: cannot be added at the moment, try again
- unable to add account %q to the list of dedicated routes: %v
- invalid ClientAdvertise value of %s, err=%v
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/2d96ab065c121b8b.
Report an issue: GitHub.