Early preview of .Net8 builds, codename `2.0.8.106`

As announced in the latest canary, the plan is to move to .Net8 builds going forward.
For those that want to help out or try the very latest, I have prepared a set of builds that use the .Net8 build & package process.

I hope this will be the last debug build and that we will be able to release canary builds going forward.

This build has a number of fixes reported on the previous builds:

  • Even better libicu support
  • New updater manifest
  • Storj bundling re-enabled
  • Built-in RC4 decryption
  • Restored tray-icons to their former glory
  • Reduced Dynamic Loader
  • Minor adjustments to SSL flags
  • Multiple report destinations, split json and form posts

The packages are signed (Windows + MacOS) and the GPG signatures are included.

Upgrade notice

Since RC4 encryption is no longer part of the open-source SQLite libraries, the builds will detect and remove the RC4 encryption before connecting to the database. If your security setup previously depended on this feature, make sure to adjust.

The file naming structure:

The filenames are named after operating system, chip architecture and intended use, e.g. linux-x64-gui.
The -gui builds also include the cli executable, but are generally bigger due to the UI libraries.

The suffix denotes the installer type:

  • .zip: Generally just the files, zipped.
  • .deb: Debian package
  • .rpm: RPM package
  • .pkg, .dmg: MacOS packages
  • .msi: Windows Installer

List of images

Trying this on my Debian 12 laptop that runs KDE Plasma. I first stopped and removed the 2.0.7.100 version (using apt purge). I then installed the GUI deb packaged.

When I attempt to start the new version with my previous sqlite databases present, it crashes:

Newtonsoft.Json.JsonSerializationException: Error getting value from 'UpdateDownloadLink' on 'Duplicati.Server.Serializable.ServerStatus'.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Duplicati.Library.AutoUpdater.UpdateInfo.GetGenericUpdatePageUrl(String packageTypeId)
   at Duplicati.Library.AutoUpdater.UpdateInfo.GetUpdateUrls(String packageTypeId)
   at Duplicati.Server.Serializable.ServerStatus.get_UpdateDownloadLink()
   at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
   at Duplicati.Server.Serialization.Serializer.SerializeJsonAsync(TextWriter tw, Object o, Boolean preventDispose)
   at Duplicati.Server.WebServer.BodyWriter.<>c__DisplayClass8_0.<<WriteJsonObject>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Duplicati.Server.WebServer.BodyWriter.WriteJsonObject(Object o)
   at Duplicati.Server.WebServer.BodyWriter.OutputOK(Object result)
   at Duplicati.Server.WebServer.RESTMethods.RequestInfo.OutputOK(Object item)
   at Duplicati.Server.WebServer.RESTMethods.ServerState.GET(String key, RequestInfo info)
   at Duplicati.Server.WebServer.RESTHandler.DoProcess(RequestInfo info, String method, String module, String key)
Request error: System.Net.WebException: The remote server returned an error: (500) Error.
   at Duplicati.Library.Utility.AsyncHttpRequest.AsyncWrapper.GetResponseOrStream()
   at Duplicati.Library.Utility.AsyncHttpRequest.GetResponse()
   at Duplicati.GUI.TrayIcon.HttpServerConnection.PerformRequestInternal[T](String method, String endpoint, Dictionary`2 queryparams)
   at Duplicati.GUI.TrayIcon.HttpServerConnection.PerformRequest[T](String method, String urlfragment, Dictionary`2 queryparams)
   at Duplicati.GUI.TrayIcon.HttpServerConnection.UpdateStatus()
   at Duplicati.GUI.TrayIcon.HttpServerConnection..ctor(Uri server, String password, Boolean saltedpassword, PasswordSource passwordSource, Boolean disableTrayIconLogin, Dictionary`2 options)
   at Duplicati.GUI.TrayIcon.Program.StartTray(String[] _args, Dictionary`2 options, HostedInstanceKeeper hosted, String password, Boolean saltedpassword)
Newtonsoft.Json.JsonSerializationException: Error getting value from 'UpdateDownloadLink' on 'Duplicati.Server.Serializable.ServerStatus'.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Duplicati.Library.AutoUpdater.UpdateInfo.GetGenericUpdatePageUrl(String packageTypeId)
   at Duplicati.Library.AutoUpdater.UpdateInfo.GetUpdateUrls(String packageTypeId)
   at Duplicati.Server.Serializable.ServerStatus.get_UpdateDownloadLink()
   at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
   at Duplicati.Server.Serialization.Serializer.SerializeJsonAsync(TextWriter tw, Object o, Boolean preventDispose)
   at Duplicati.Server.WebServer.BodyWriter.<>c__DisplayClass8_0.<<WriteJsonObject>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Duplicati.Server.WebServer.BodyWriter.WriteJsonObject(Object o)
   at Duplicati.Server.WebServer.BodyWriter.OutputOK(Object result)
   at Duplicati.Server.WebServer.RESTMethods.RequestInfo.OutputOK(Object item)
   at Duplicati.Server.WebServer.RESTMethods.ServerState.GET(String key, RequestInfo info)
   at Duplicati.Server.WebServer.RESTHandler.DoProcess(RequestInfo info, String method, String module, String key)
Request error: System.Net.WebException: The remote server returned an error: (500) Error.
   at Duplicati.Library.Utility.AsyncHttpRequest.AsyncWrapper.GetResponseOrStream()
   at Duplicati.Library.Utility.AsyncHttpRequest.GetResponse()
   at Duplicati.GUI.TrayIcon.HttpServerConnection.PerformRequestInternal[T](String method, String endpoint, Dictionary`2 queryparams)
   at Duplicati.GUI.TrayIcon.HttpServerConnection.PerformRequest[T](String method, String urlfragment, Dictionary`2 queryparams)
   at Duplicati.GUI.TrayIcon.HttpServerConnection.UpdateStatus()
   at Duplicati.GUI.TrayIcon.HttpServerConnection..ctor(Uri server, String password, Boolean saltedpassword, PasswordSource passwordSource, Boolean disableTrayIconLogin, Dictionary`2 options)
   at Duplicati.GUI.TrayIcon.Program.StartTray(String[] _args, Dictionary`2 options, HostedInstanceKeeper hosted, String password, Boolean saltedpassword)
Newtonsoft.Json.JsonSerializationException: Error getting value from 'UpdateDownloadLink' on 'Duplicati.Server.Serializable.ServerStatus'.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Duplicati.Library.AutoUpdater.UpdateInfo.GetGenericUpdatePageUrl(String packageTypeId)
   at Duplicati.Library.AutoUpdater.UpdateInfo.GetUpdateUrls(String packageTypeId)
   at Duplicati.Server.Serializable.ServerStatus.get_UpdateDownloadLink()
   at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
   at Duplicati.Server.Serialization.Serializer.SerializeJsonAsync(TextWriter tw, Object o, Boolean preventDispose)
   at Duplicati.Server.WebServer.BodyWriter.<>c__DisplayClass8_0.<<WriteJsonObject>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Duplicati.Server.WebServer.BodyWriter.WriteJsonObject(Object o)
   at Duplicati.Server.WebServer.BodyWriter.OutputOK(Object result)
   at Duplicati.Server.WebServer.RESTMethods.RequestInfo.OutputOK(Object item)
   at Duplicati.Server.WebServer.RESTMethods.ServerState.GET(String key, RequestInfo info)
   at Duplicati.Server.WebServer.RESTHandler.DoProcess(RequestInfo info, String method, String module, String key)
Request error: System.Net.WebException: The remote server returned an error: (500) Error.
   at Duplicati.Library.Utility.AsyncHttpRequest.AsyncWrapper.GetResponseOrStream()
   at Duplicati.Library.Utility.AsyncHttpRequest.GetResponse()
   at Duplicati.GUI.TrayIcon.HttpServerConnection.PerformRequestInternal[T](String method, String endpoint, Dictionary`2 queryparams)
   at Duplicati.GUI.TrayIcon.HttpServerConnection.PerformRequest[T](String method, String urlfragment, Dictionary`2 queryparams)
   at Duplicati.GUI.TrayIcon.HttpServerConnection.UpdateStatus()
   at Duplicati.GUI.TrayIcon.HttpServerConnection..ctor(Uri server, String password, Boolean saltedpassword, PasswordSource passwordSource, Boolean disableTrayIconLogin, Dictionary`2 options)
   at Duplicati.GUI.TrayIcon.Program.StartTray(String[] _args, Dictionary`2 options, HostedInstanceKeeper hosted, String password, Boolean saltedpassword)

If I remove the ~/.config/Duplicati folder and try starting it, it gets a bit farther in that it opens my web browser at the Duplicati server url, but then it crashes with this error:

Unexpected error: System.IO.FileNotFoundException: The resource avares://Duplicati.GUI.TrayIcon.Implementation, Version=2.0.8.106, Culture=neutral, PublicKeyToken=null/Assets/icons/linux/context-menu-open.png could not be found.
   at Avalonia.Platform.StandardAssetLoader.OpenAndGetAssembly(Uri uri, Uri baseUri)
   at Avalonia.Platform.StandardAssetLoader.Open(Uri uri, Uri baseUri)
   at Avalonia.Platform.AssetLoader.Open(Uri uri, Uri baseUri)
   at Duplicati.GUI.TrayIcon.AvaloniaRunner.LoadBitmap(String iconName)
   at Duplicati.GUI.TrayIcon.AvaloniaMenuItem.UpdateIcon()
   at Duplicati.GUI.TrayIcon.AvaloniaMenuItem.GetNativeItem()
   at Duplicati.GUI.TrayIcon.AvaloniaApp.SetMenu(IEnumerable`1 menuItems)
   at Duplicati.GUI.TrayIcon.AvaloniaRunner.Run(String[] args, Action postInit)
   at Duplicati.GUI.TrayIcon.TrayIconBase.Init(String[] args)
   at Duplicati.GUI.TrayIcon.AvaloniaRunner.Init(String[] args)
   at Duplicati.GUI.TrayIcon.Program.StartTray(String[] _args, Dictionary`2 options, HostedInstanceKeeper hosted, String password, Boolean saltedpassword)

Thanks for testing!

I will fix these two issues asap.

1 Like

Also, the tray icon never appears but maybe that’s from the process crashing on startup.

probably explains why 2.0.8.105 “Check for updates now” errors into the server log with

May 3, 2024 2:01 PM: Error in updater
System.IO.InvalidDataException: Unable to verify signature
   at Duplicati.Library.Utility.SignatureReadingStream..ctor(Stream stream, IEnumerable`1 keys)
   at Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate(ReleaseType channel)

and

C:\Program Files\Duplicati 2>Duplicati.CommandLine.AutoUpdater.exe check
Error detected: System.IO.InvalidDataException: Unable to verify signature
   at Duplicati.Library.Utility.SignatureReadingStream..ctor(Stream stream, IEnumerable`1 keys)
   at Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate(ReleaseType channel)
Error detected: System.IO.InvalidDataException: Unable to verify signature
   at Duplicati.Library.Utility.SignatureReadingStream..ctor(Stream stream, IEnumerable`1 keys)
   at Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate(ReleaseType channel)
No updates found

but I’m less sure about this:

C:\Program Files\Duplicati 2>Duplicati.CommandLine.AutoUpdater.exe
Unhandled exception. System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
   at System.Text.ValueStringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ReadOnlySpan`1 args)
   at System.IO.StreamWriter.WriteFormatHelper(String format, ReadOnlySpan`1 args, Boolean appendNewLine)
   at System.IO.StreamWriter.WriteLine(String format, Object arg0, Object arg1)
   at System.IO.TextWriter.SyncTextWriter.WriteLine(String format, Object arg0, Object arg1)
   at System.Console.WriteLine(String format, Object arg0, Object arg1)
   at Duplicati.Library.AutoUpdater.Program.WriteUsage()
   at Duplicati.Library.AutoUpdater.Program.Main(String[] _args)
   at Duplicati.CommandLine.AutoUpdater.Net8.Program.Main(String[] args)

but note that this is 2.0.8.105 code trying to check for updates. Maybe I’ll just do 2.0.8.106 directly.

I’m also just now noticing that the AutoUpdater.exe file got renamed from Library to CommandLine.
This actually makes more sense, and the whole scheme is so different that some differences show.

Installed from duplicati-2.0.8.106_debug_2024-05-03-win-x64-gui.msi and got basically no .exe files.
Technically there’s an old “C:\Program Files\Duplicati 2\win-tools\gpgconf.exe”, but that’s little help…

I did this install with 2.0.8.105 still running as Windows service, then got surprised on restart request.

Similar to @ts678, I installed from duplicati-2.0.8.106_debug_2024-05-03-win-x64-gui.msi over an existing install of 2.0.8.105 and ended up with no executable files. I was also running Duplicati as a service on Windows.

Opting instead for a clean install, I uninstalled Duplicati and then reinstalled it with the 2.0.8.106 .msi. I left my data directory in place so in theory it would be inherited. I had all the executable files this time, but I couldn’t get the service to start. After some playing around I discovered that the server was starting, but only port 8300 instead of 8200. This was odd, because I didn’t have any other instances of Duplicati running. Also, once I opened the page and attempted to do anything at all the service would stop responding.

Ultimately, I wasn’t able to get it to work at all without deleting my duplicati-server.sqlite file and allowing it to create a new, empty one.

If I used an old copy of my manually decrypted database I could get 2.8.0.6 to start and require me to enter a password, but all my backup jobs would be missing.

Not sure what to make of all this at the moment, I’m a bit constrained for time so I can’t look into it further.

Couple last bits of data. I can’t access the GUI, but it does appear that my backups are being run in the background as I see a lot of disk and network activity. I can’t actually see the job in the UI, and the UI goes completely unresponsive in about 5-10 seconds and stays that way until I restart the service.

I don’t usually run the tray icon at all, but when I do I get this message:

Trying a .zip file install of duplicati-2.0.8.106_debug_2024-05-03-win-x64-gui.zip, AutoUpdater still fails:

C:\Duplicati\duplicati-2.0.8.106_debug_2024-05-03-win-x64-gui>Duplicati.CommandLine.AutoUpdater.exe
Unhandled exception. System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
   at System.Text.ValueStringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ReadOnlySpan`1 args)
   at System.IO.StreamWriter.WriteFormatHelper(String format, ReadOnlySpan`1 args, Boolean appendNewLine)
   at System.IO.StreamWriter.WriteLine(String format, Object arg0, Object arg1)
   at System.IO.TextWriter.SyncTextWriter.WriteLine(String format, Object arg0, Object arg1)
   at System.Console.WriteLine(String format, Object arg0, Object arg1)
   at Duplicati.Library.AutoUpdater.Program.WriteUsage()
   at Duplicati.Library.AutoUpdater.Program.Main(String[] _args)
   at Duplicati.CommandLine.AutoUpdater.Net8.Program.Main(String[] args)

C:\Duplicati\duplicati-2.0.8.106_debug_2024-05-03-win-x64-gui>Duplicati.CommandLine.AutoUpdater.exe check
Error detected: System.InvalidOperationException: No verify operations provided, cannot verify data
   at Duplicati.Library.Utility.JSONSignature.Verify(Stream source, IEnumerable`1 verifyOperations)
   at Duplicati.Library.Utility.JSONSignature.VerifyAtLeastOne(Stream source, IEnumerable`1 verifyOperations)
   at Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate(ReleaseType channel)
Error detected: System.InvalidOperationException: No verify operations provided, cannot verify data
   at Duplicati.Library.Utility.JSONSignature.Verify(Stream source, IEnumerable`1 verifyOperations)
   at Duplicati.Library.Utility.JSONSignature.VerifyAtLeastOne(Stream source, IEnumerable`1 verifyOperations)
   at Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate(ReleaseType channel)
No updates found

C:\Duplicati\duplicati-2.0.8.106_debug_2024-05-03-win-x64-gui>

Duplicati.GUI.TrayIcon.exe crashes very fast, less than a minute. At this point, I’m running it from a script without an existing Duplicati-server.sqlite, but using Duplicati.Server.exe to make one doesn’t fix TrayIcon.

One good piece of progress is that I saw a nice looking TrayIcon flash by in the system tray before it died.

No event in the application log talking about its death (some of earlier crashes did make event log entries).

There is a server profiling log, and it did show some of the startup as

2024-05-03 18:35:35 -04 - [Information-Duplicati.Server.WebServer.Server-ServerListening]: Server has started and is listening on 127.0.0.1, port 8300

and 8300 is because 2.0.8.0 Experimental has 8200.

On further review, I just noticed that the logs were full of these:

For some reason the files were named context_menu_open.png instead of context-menu-open.png.

.105 is likely broken in terms of the updater. It looks at the previous manifest file, but expects the structure for the new file.

That sounds exactly like the upgrade issue we found earlier, where the MSI will remove all the exe files after install :confused:

I know there are some issue if you do not exit Duplicati before upgrading with the MSI.
In your case, did you simply install .105 and then .106 and reboot?

That is a mistake on my end. I was running multiple instances for testing, and this slipped into the build.

That was a bug after I removed mono mentions :frowning:
The other one was caused by the change to support multiple signing keys.

I think this is similar to the linux issue. I can see that the Windows png’s were missing for some reason.

I think I have a fix for these now. It is caused by having an existing install that contains a cached copy of the updater file inside the database.

This worries me a bit, because I have not seen anything like this in my testing.

I assume this is on Windows.
To reproduce, I would

  • install 2.0.7.1
  • create a backup
  • run it
  • check for updates
  • quit
  • install 2.0.8.106

Does that sound resonable?

I think you covered this later in your post, responding to 106 notes, but here’s the story as it unfolded for me:

105 stack and 106 stack show it fails in WriteUsage() when no operation is given. When check is requested, 105 fails with "Unable to verify signature) but 106 fails with “No verify operations provided, cannot verify data”. Explanation of manifest file differences seems to explain neither of the 106 failures, but maybe one of the 105.

Giving it help rather than nothing doesn’t help to get the help.

C:\Duplicati\duplicati-2.0.8.106_debug_2024-05-03-win-x64-gui>Duplicati.CommandLine.AutoUpdater.exe help
Unhandled exception. System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
   at System.Text.ValueStringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ReadOnlySpan`1 args)
   at System.IO.StreamWriter.WriteFormatHelper(String format, ReadOnlySpan`1 args, Boolean appendNewLine)
   at System.IO.StreamWriter.WriteLine(String format, Object arg0, Object arg1)
   at System.IO.TextWriter.SyncTextWriter.WriteLine(String format, Object arg0, Object arg1)
   at System.Console.WriteLine(String format, Object arg0, Object arg1)
   at Duplicati.Library.AutoUpdater.Program.WriteUsage()
   at Duplicati.Library.AutoUpdater.Program.Main(String[] _args)
   at Duplicati.CommandLine.AutoUpdater.Net8.Program.Main(String[] args)

I thought someone will do that, so thought I might as well try it to see what results from it.

If it helps, I could probably back up to 105 and see if things go better with Duplicati down.

involves an old install, and I (maybe overly) simply tested installing 106 over it (which gave no complaint), however the Restart the service attempt in an elevated administrator services manager failed, since executable wasn’t there. There was no Windows reboot.

Pretty close … not sure it matters, but my scenario would be more like:

  • Existing install of 2.0.7.1 running as a service that was created many past versions ago and has been upgraded over the years.
  • Stop existing service
  • Install 2.0.8.106
  • Start service

I have an updated response in the 2.0.8.107 thread. I believe the problem in that one is in the database. If I manually decrypt it, I am able to start and run the service.