I just watched one of these, and have some technical notes. The easiest way to see the resource leak is to watch Task Manager GDI Objects column. The default limit is 10000. Mine was reliably going up by 3 every minute. Watching Wireshark revealed a 5 minute longpoll from TrayIcon returning after a minute with new LastEventID, then count jumps.
GET /api/v1/serverstate?longpoll=true&lastEventId=3340&duration=5m HTTP/1.1
Host: localhost:8005
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXAiOiJBY2Nlc3NUb2tlbiIsInNpZCI6InRyYXlpY29uIiwiZmFtIjoidGVtcG9yYXJ5IiwibmJmIjoxNzU2MTQxNDI2LCJleHAiOjE3NTYxNDIzMjYsImlzcyI6Imh0dHBzOi8vZHVwbGljYXRpIiwiYXVkIjoiaHR0cHM6Ly9kdXBsaWNhdGkifQ.HQhkXw1-N-w4KMqNWqaUvPjc_P6H0aU3_OIRYDday3k
User-Agent: Duplicati-TrayIcon-Monitor/2.1.0.5
60.008633s
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Mon, 25 Aug 2025 17:14:46 GMT
Server: Kestrel
Transfer-Encoding: chunked
0.000000s
{"ActiveTask":null,"ProgramState":"Running","SchedulerQueueIds":[],"ProposedSchedule":[],"HasWarning":false,"HasError":false,"SuggestedStatusIcon":"Ready","EstimatedPauseEnd":"0001-01-01T00:00:00","LastEventID":3341,"LastDataUpdateID":38,"LastNotificationUpdateID":16,"UpdatedVersion":null,"UpdaterState":"Waiting","UpdateDownloadLink":null,"UpdateDownloadProgress":0}
0.002221s
GET /api/v1/serverstate?longpoll=true&lastEventId=3341&duration=5m HTTP/1.1
Host: localhost:8005
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXAiOiJBY2Nlc3NUb2tlbiIsInNpZCI6InRyYXlpY29uIiwiZmFtIjoidGVtcG9yYXJ5IiwibmJmIjoxNzU2MTQxNDI2LCJleHAiOjE3NTYxNDIzMjYsImlzcyI6Imh0dHBzOi8vZHVwbGljYXRpIiwiYXVkIjoiaHR0cHM6Ly9kdXBsaWNhdGkifQ.HQhkXw1-N-w4KMqNWqaUvPjc_P6H0aU3_OIRYDday3k
User-Agent: Duplicati-TrayIcon-Monitor/2.1.0.5
60.007676s
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Mon, 25 Aug 2025 17:15:46 GMT
Server: Kestrel
Transfer-Encoding: chunked
0.000000s
{"ActiveTask":null,"ProgramState":"Running","SchedulerQueueIds":[],"ProposedSchedule":[],"HasWarning":false,"HasError":false,"SuggestedStatusIcon":"Ready","EstimatedPauseEnd":"0001-01-01T00:00:00","LastEventID":3342,"LastDataUpdateID":38,"LastNotificationUpdateID":16,"UpdatedVersion":null,"UpdaterState":"Waiting","UpdateDownloadLink":null,"UpdateDownloadProgress":0}
Upon crash, I couldn’t find anything in the various event logs I checked, but console got:
C:\Duplicati\duplicati-2.1.0.5_stable_2025-03-04-win-x64-gui\RUN>pause
Press any key to continue . . . Server has started and is listening on port 8005
Unexpected error: System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully.
at Avalonia.Win32.Interop.Win32Icon.CreateIcon(Bitmap bitmap, PixelPoint hotSpot)
at Avalonia.Win32.Interop.Win32Icon..ctor(Win32Icon original, PixelSize size)
at Avalonia.Win32.TrayIconImpl.UpdateIcon(Boolean remove)
at Avalonia.Controls.TrayIcon.OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
at Avalonia.AvaloniaObject.RaisePropertyChanged[T](AvaloniaProperty`1 property, Optional`1 oldValue, BindingValue`1 newValue, BindingPriority priority, Boolean isEffectiveValue)
at Avalonia.PropertyStore.EffectiveValue`1.NotifyValueChanged(ValueStore owner, StyledProperty`1 property, T oldValue)
at Avalonia.PropertyStore.EffectiveValue`1.SetAndRaiseCore(ValueStore owner, StyledProperty`1 property, T value, BindingPriority priority, Boolean isOverriddenCurrentValue, Boolean isCoercedDefaultValue)
at Duplicati.GUI.TrayIcon.AvaloniaApp.SetIcon(TrayIcons icon)
at Avalonia.Threading.DispatcherOperation.InvokeCore()
at Avalonia.Threading.DispatcherOperation.Execute()
at Avalonia.Threading.Dispatcher.ExecuteJob(DispatcherOperation job)
at Avalonia.Threading.Dispatcher.ExecuteJobsCore(Boolean fromExplicitBackgroundProcessingCallback)
at Avalonia.Threading.Dispatcher.Signaled()
at Avalonia.Win32.Win32Platform.WndProc(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam)
at Avalonia.Win32.Interop.UnmanagedMethods.DispatchMessage(MSG& lpmsg)
at Avalonia.Win32.Win32DispatcherImpl.RunLoop(CancellationToken cancellationToken)
at Avalonia.Threading.DispatcherFrame.Run(IControlledDispatcherImpl impl)
at Avalonia.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at Avalonia.Threading.Dispatcher.MainLoop(CancellationToken cancellationToken)
at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.StartCore(String[] args)
at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[] args)
at Duplicati.GUI.TrayIcon.AvaloniaRunner.Run(String[] args)
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, String acceptedHostCertificate)
An error occurred on server tear down: System.Threading.ThreadInterruptedException: Thread was interrupted from a waiting state.
at System.Threading.Monitor.ObjWait(Int32 millisecondsTimeout, Object obj)
at System.Threading.ManualResetEventSlim.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.SpinThenBlockingWait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.InternalWaitCore(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at Duplicati.Server.Program.ShutdownModernWebserver()
at Duplicati.Server.Program.<>c.<Main>b__60_9()
at Duplicati.Server.Program.Main(String[] _args)
I’m not sure if the longpoll changing like this is normal, but it seems to drive the problem.
Recent Canary and Beta Duplicati seem to last full 5 minute longpoll and don’t leak GDI. LastEventID stays steady while idle, unlike 2.1.0.5, at least in steady march to the crash.
Surprisingly, I can’t find many reports of this, at least ones where the stack was obtained.
Duplicati Client crashes and/or quits every few days was the other in forum.
Restarting 2.1.0.5 and letting it idle is doing the 1 minute new LastEventID and GDI jump.