diff --git a/Duplicati/Library/RestAPI/Runner.cs b/Duplicati/Library/RestAPI/Runner.cs
index 8640e8ad6..0eeca7139 100644
--- a/Duplicati/Library/RestAPI/Runner.cs
+++ b/Duplicati/Library/RestAPI/Runner.cs
@@ -1412,6 +1412,19 @@ namespace Duplicati.Server
options["remote-sync-json-config"] = JsonSerializer.Serialize(config, jsonOptions);
}
+ ///
+ /// Returns the effective local database path for a backup: the "--dbpath" advanced option if
+ /// it is set, otherwise the stored . This
+ /// mirrors the precedence applied by so that every operation agrees
+ /// on which database file to use (see issue #1698).
+ ///
+ public static string GetEffectiveDBPath(Serialization.Interface.IBackup backup)
+ {
+ var dbpath = backup.Settings?
+ .FirstOrDefault(s => s.Name.Equals("--dbpath", StringComparison.OrdinalIgnoreCase))?.Value;
+ return string.IsNullOrWhiteSpace(dbpath) ? backup.DBPath : dbpath;
+ }
+
internal static Dictionary ApplyOptions(Connection databaseConnection, Serialization.Interface.IBackup backup, Dictionary options, out string url)
{
url = backup.TargetURL;
diff --git a/Duplicati/UnitTest/Issue1698.cs b/Duplicati/UnitTest/Issue1698.cs
new file mode 100644
index 000000000..bb571e04f
--- /dev/null
+++ b/Duplicati/UnitTest/Issue1698.cs
@@ -0,0 +1,91 @@
+// Copyright (C) 2026, The Duplicati Team
+// https://duplicati.com, hello@duplicati.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Duplicati.Server.Database;
+using Duplicati.Server.Serialization.Interface;
+using NUnit.Framework;
+using Assert = NUnit.Framework.Legacy.ClassicAssert;
+
+namespace Duplicati.UnitTest
+{
+ ///
+ /// https://github.com/duplicati/duplicati/issues/1698
+ /// "Show log" and "Database delete" read/deleted the stored Backup.DBPath directly, while
+ /// most operations honor a "--dbpath" advanced option. When those disagreed, Show log opened the
+ /// wrong/empty database ("no such table: LogData").
+ /// reconciles them with the same precedence as the runner; these tests cover that precedence.
+ ///
+ [TestFixture]
+ public class Issue1698
+ {
+ private static Backup CreateBackup(string? storedDbPath, params (string Name, string Value)[] settings)
+ {
+ var backup = new Backup
+ {
+ ID = null,
+ Name = "Test Backup",
+ Description = "",
+ Tags = new string[0],
+ TargetURL = "file:///test",
+ Sources = new string[0],
+ Settings = settings.Select(s => (ISetting)new Setting { Name = s.Name, Value = s.Value }).ToArray(),
+ Filters = new IFilter[0],
+ Metadata = new Dictionary()
+ };
+ if (storedDbPath != null)
+ backup.SetDBPath(storedDbPath);
+ return backup;
+ }
+
+ [Test]
+ public void UsesStoredDbPathWhenNoAdvancedOption()
+ {
+ var backup = CreateBackup("/stored/path.sqlite");
+ Assert.AreEqual("/stored/path.sqlite", Duplicati.Server.Runner.GetEffectiveDBPath(backup));
+ }
+
+ [Test]
+ public void AdvancedDbPathOptionOverridesStoredDbPath()
+ {
+ var backup = CreateBackup("/stored/path.sqlite", ("--dbpath", "/override/path.sqlite"));
+ Assert.AreEqual("/override/path.sqlite", Duplicati.Server.Runner.GetEffectiveDBPath(backup));
+ }
+
+ [Test]
+ public void AdvancedDbPathMatchIsCaseInsensitiveOnName()
+ {
+ var backup = CreateBackup("/stored/path.sqlite", ("--DBPath", "/override/path.sqlite"));
+ Assert.AreEqual("/override/path.sqlite", Duplicati.Server.Runner.GetEffectiveDBPath(backup));
+ }
+
+ [Test]
+ public void BlankAdvancedDbPathFallsBackToStoredDbPath()
+ {
+ var backup = CreateBackup("/stored/path.sqlite", ("--dbpath", " "));
+ Assert.AreEqual("/stored/path.sqlite", Duplicati.Server.Runner.GetEffectiveDBPath(backup));
+ }
+ }
+}
diff --git a/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupGet.cs b/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupGet.cs
index c0f7a5a9e..3228fba0e 100644
--- a/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupGet.cs
+++ b/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupGet.cs
@@ -187,20 +187,24 @@ public class BackupGet : IEndpointV1
private static List> ExecuteGetLog(Connection connection, IBackup bk, long? offset, long pagesize)
{
- if (!File.Exists(bk.DBPath))
+ // Use the effective database path (honoring a "--dbpath" advanced option) so that the log is
+ // read from the same database the backup actually uses (see issue #1698).
+ var dbpath = Runner.GetEffectiveDBPath(bk);
+ if (!File.Exists(dbpath))
return new List>();
- using (var con = Library.SQLiteHelper.SQLiteLoader.LoadConnection(bk.DBPath))
+ using (var con = Library.SQLiteHelper.SQLiteLoader.LoadConnection(dbpath))
using (var cmd = con.CreateCommand())
return LogData.DumpTable(cmd, "LogData", "ID", offset, pagesize);
}
private static List> ExecuteGetRemotelog(Connection connection, IBackup bk, long? offset, long pagesize)
{
- if (!File.Exists(bk.DBPath))
+ var dbpath = Runner.GetEffectiveDBPath(bk);
+ if (!File.Exists(dbpath))
return new List>();
- using (var con = Library.SQLiteHelper.SQLiteLoader.LoadConnection(bk.DBPath))
+ using (var con = Library.SQLiteHelper.SQLiteLoader.LoadConnection(dbpath))
using (var cmd = con.CreateCommand())
{
var dt = LogData.DumpTable(cmd, "RemoteOperation", "ID", offset, pagesize);
diff --git a/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupPost.cs b/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupPost.cs
index c95cf956f..faa64b78c 100644
--- a/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupPost.cs
+++ b/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupPost.cs
@@ -105,7 +105,9 @@ public class BackupPost : IEndpointV1
=> connection.GetBackup(id) ?? throw new NotFoundException("Backup not found");
private static void ExecuteDeleteDb(IBackup backup)
- => File.Delete(backup.DBPath);
+ // Delete the effective database (honoring a "--dbpath" advanced option) so the database the
+ // backup actually uses is removed, not a stale DBPath that may not exist (see issue #1698).
+ => File.Delete(Runner.GetEffectiveDBPath(backup));
private static void UpdateDatabasePath(Connection connection, IBackup backup, string targetpath, bool move)
{