Code change:
--retry 1000 --retry-delay 1 --retry-all-errors  "$@" } <del> # query the old config old_cfg=$(curl ${cfg.guiAddress}/rest/config) # generate the new config by merging with the NixOS config options new_cfg=$(printf '%sn' "$old_cfg" | ${pkgs.jq}/bin/jq -c ${escapeShellArg ''. * ${builtins.toJSON cleanedConfig} * { "devices": ('${escapeShellArg (builtins.toJSON devices)}'${optionalString (cfg.settings.devices == {} || ! cfg.overrideDevices) " + .devices"}), "folders": ('${escapeShellArg (builtins.toJSON folders)}'${optionalString (cfg.settings.folders == {} || ! cfg.overrideFolders) " + .folders"}) }''}) # send the new config curl -X PUT -d "$new_cfg" ${cfg.guiAddress}/rest/config </del> <ins> '' + /* Syncthing's rest API for the folders and devices is almost identical. Hence we iterate them using lib.pipe and generate shell commands for both at the sime time. */ (lib.pipe { # The attributes below are the only ones that are different for devices / # folders. devs = { new_conf_IDs = map (v: v.id) devices; GET_IdAttrName = "deviceID"; override = cfg.overrideDevices; conf = devices; baseAddress = "${cfg.guiAddress}/rest/config/devices"; }; dirs = { new_conf_IDs = map (v: v.id) folders; GET_IdAttrName = "id"; override = cfg.overrideFolders; conf = folders; baseAddress = "${cfg.guiAddress}/rest/config/folders"; }; } [ # Now for each of these attributes, write the curl commands that are # identical to both folders and devices. (mapAttrs (conf_type: s: # We iterate the `conf` list now, and run a curl -X POST command for each, that # should update that device/folder only. lib.pipe s.conf [ # Quoting https://docs.syncthing.net/rest/config.html: # # > PUT takes an array and POST a single object. In both cases if a # given folder/device already exists, it’s replaced, otherwise a new # one is added. # # What's not documented, is that using PUT will remove objects that # don't exist in the array given. That's why we use here `POST`, and # only if s.override == true then we DELETE the relevant folders # afterwards. (map (new_cfg: '' curl -d ${lib.escapeShellArg (builtins.toJSON new_cfg)} -X POST ${s.baseAddress} '')) (lib.concatStringsSep "n") ] /* If we need to override devices/folders, we iterate all currently configured IDs, via another `curl -X GET`, and we delete all IDs that are not part of the Nix configured list of IDs */ + lib.optionalString s.override '' old_conf_${conf_type}_ids="$(curl -X GET ${s.baseAddress} | ${jq} --raw-output '.[].${s.GET_IdAttrName}')" for id in ''${old_conf_${conf_type}_ids}; do if echo ${lib.concatStringsSep " " s.new_conf_IDs} | grep -q $id; then continue else curl -X DELETE ${s.baseAddress}/$id fi done '' )) builtins.attrValues (lib.concatStringsSep "n") ]) + /* Now we update the other settings defined in cleanedConfig which are not "folders" or "devices". */ (lib.pipe cleanedConfig [ builtins.attrNames (lib.subtractLists ["folders" "devices"]) (map (subOption: '' curl -X PUT -d ${lib.escapeShellArg (builtins.toJSON cleanedConfig.${subOption})}  ${cfg.guiAddress}/rest/config/${subOption} '')) (lib.concatStringsSep "n") ]) + '' </ins> # restart Syncthing if required if curl ${cfg.guiAddress}/rest/config/restart-required | <del> ${pkgs.jq}/bin/jq -e .requiresRestart > /dev/null; then </del> <ins> ${jq} -e .requiresRestart > /dev/null; then </ins> curl -X POST ${cfg.guiAddress}/rest/system/restart fi <del> ''; </del> <ins> ''); </ins> in { ###### interface options = {

Related discussion:
text: I'm experiencing the issue for a long time now, and it was really hard to spot and debug this issue. I'm talking about this line: It's kind of hard to give instructions how to reproduce the issue. In my case, whenever the dash script runs, every folder I already have configured, fails to update. The whole configuration thus fails to be uploaded to the server. I can inspect the and the by editing that dash script, and I can see that I get folders twice in the json arrays. Hence I'm not surprised I see the following error in syncthing's web interface: ! I expect the merge script to not a JSON array with no duplicate folders IDs. Transition most of the logic from jq to bash, for easier maintenance, and use and API, and use when . I'm working on a solution at the moment but I'd like to here your comments first. cc who wrote the original dash script, other people have touched that line ever since, was the latest.