{"record":{"id":"451f777fc49fbc0a","repo":"nats-io/nats-server","slug":"field-users-old-v-new-v","errorCode":null,"errorMessage":"field \"Users\": old=%v, new=%v","messagePattern":"field \"Users\": old=(.+?), new=(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/reload.go","lineNumber":925,"sourceCode":"\tadded   []*RemoteLeafOpts\n\tchanged map[*leafNodeCfg]*remoteLeafOption\n}\n\ntype remoteLeafOption struct {\n\ttlsFirstChanged    bool\n\tcompressionChanged bool\n\tdisabledChanged    bool\n\topts               *RemoteLeafOpts\n}\n\n// Given `old` and `new` Leafnode options, this function will return the structure\n// used for applying the configuration, or an error is there are changes that\n// are not supported.\nfunc getLeafNodeOptionsChanges(s *Server, old, new *LeafNodeOpts) (*leafNodeOption, error) {\n\n\t// We can't use DeepEqual for `Users` field, so do custom check.\n\tif usersHaveChanged(old.Users, new.Users) {\n\t\treturn nil, fmt.Errorf(\"field \\\"Users\\\": old=%v, new=%v\", old.Users, new.Users)\n\t}\n\n\t// Check the main leafnodes{} block to see if there are any changes that are\n\t// not supported. We provide a list of fields to ignore (we already checked,\n\t// allow them to be modified or will check later).\n\tif err := checkConfigsEqual(old, new, []string{\n\t\t\"Compression\",\n\t\t\"Remotes\",\n\t\t\"TLSHandshakeFirst\",\n\t\t\"TLSHandshakeFirstFallback\",\n\t\t\"TLSConfig\",\n\t\t\"Users\",\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\tconst (\n\t\tremoteErrFormat = \"remote %s: %s\"","sourceCodeStart":907,"sourceCodeEnd":943,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/reload.go#L907-L943","documentation":"During config reload, getLeafNodeOptionsChanges compares old and new leafnodes{} options. The Users field cannot be compared with DeepEqual, so usersHaveChanged() is used; if the user credentials list differs, reload fails because changing leaf node users on the fly is unsupported.","triggerScenarios":"Modifying the users array of an existing leafnodes{} block (adding, removing, or changing credentials/URL users) and issuing a reload (SIGHUP or Reload()).","commonSituations":"Operators rotating leaf node credentials via config reload instead of a restart; adding a second remote account/user entry in a running server's leaf block.","solutions":["Keep the leafnodes users array identical in the reloaded config, or restart the server to apply user changes.","Change only supported leaf node fields (URLs, TLS, etc.) during reload; move user changes to a full restart/maintenance window.","If the change was accidental, revert the users section to match the running configuration."],"exampleFix":"// before (reload)\nleafnodes { users: [ {user: a, pass: x} ] }  // changed users\n// after: restart instead of reload, or keep users unchanged during reload","handlingStrategy":"validation","validationCode":"// before calling Reload(), diff configs yourself\nif !reflect.DeepEqual(oldLeaf.Users, newLeaf.Users) {\n    // schedule a full restart instead of Reload()\n    return errors.New(\"leafnodes users changed: restart required\")\n}","typeGuard":null,"tryCatchPattern":"if err := srv.Reload(); err != nil {\n    if strings.Contains(err.Error(), \"field \\\"Users\\\"\") {\n        log.Println(\"leaf users change needs a restart, not a reload\")\n    }\n}","preventionTips":["Keep leafnodes.users identical across reloads.","Treat credential rotation for leaf users as a restart-level change.","Use config linting/CI to diff user sections before issuing SIGHUP."],"tags":["reload","leafnodes","unsupported-operation"],"backgroundTag":"config-reload-unsupported-change","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}