duplicati/duplicati · error · Exception
Usage: dotnet run <path-to-source-folder> ["copyright name"]
Error message
Usage: dotnet run <path-to-source-folder> ["copyright name"]
What it means
Thrown by LinkFilesetToVolumeAsync when the UPDATE that sets Fileset.VolumeID returns a row count other than 1. The SQL updates exactly the Fileset row matching ID = @FilesetId; a result of 0 means the fileset ID does not exist, and any other count would imply a schema problem (duplicate primary key). This is a plain System.Exception (not DatabaseInconsistencyException), indicating an unexpected internal state.
Source
Thrown at BuildTools/LicenseUpdater/Program.cs:26
// 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.
using LicenseUpdater;
var cmdargs = Environment.GetCommandLineArgs();
if (cmdargs.Length != 2 && cmdargs.Length != 3)
throw new Exception($"Usage: dotnet run <path-to-source-folder> [\"copyright name\"]");
if (cmdargs.Length == 3)
Fragments.CopyrightHolder = cmdargs[2];
var startpath = Path.GetFullPath(Environment.GetCommandLineArgs().Skip(1).First());
if (!Directory.Exists(startpath))
throw new Exception($"Start path not found: {startpath}");
var target_extensions = new[] {
".cs",
".csproj"
// ".html",
// ".js",
// ".css"
}.ToHashSet(StringComparer.OrdinalIgnoreCase);
File.WriteAllText(Path.Combine(startpath, "LICENSE"), Fragments.LICENSE_FILE_HEADER + Fragments.GetLicenseTextWithPrefixedLines(string.Empty));
View on GitHub (pinned to 3f348be3e3)
Solutions
- Verify that filesetid exists in the Fileset table before calling LinkFilesetToVolumeAsync by running SELECT COUNT(*) FROM Fileset WHERE ID = @FilesetId.
- Ensure the calling code holds the correct transaction (m_rtr) and that the fileset row was committed in the same or a prior committed transaction.
- Check for concurrent delete operations that might have removed the fileset between creation and linking.
- Run the Duplicati repair command to rebuild the database if the fileset table is in an inconsistent state.
Example fix
// before
await db.LinkFilesetToVolumeAsync(filesetid, volumeid, token);
// after
var exists = await db.ExecuteScalarInt64Async(
"SELECT COUNT(*) FROM \"Fileset\" WHERE \"ID\" = @Id", token);
if (exists == 1)
await db.LinkFilesetToVolumeAsync(filesetid, volumeid, token);
else
throw new InvalidOperationException($"Fileset {filesetid} does not exist; cannot link to volume {volumeid}"); Defensive patterns
Strategy: validation
Validate before calling
// Pre-check: fileset exists before linking
long count = await db.ExecuteScalarInt64Async(
"SELECT COUNT(*) FROM \"Fileset\" WHERE \"ID\" = @Id", token);
if (count != 1)
throw new InvalidOperationException($"Fileset {filesetid} not found");
await db.LinkFilesetToVolumeAsync(filesetid, volumeid, token); Type guard
// N/A -- SQL row-count assertion, not a type issue
Try / catch
try {
await db.LinkFilesetToVolumeAsync(filesetid, volumeid, token);
} catch (Exception ex) when (ex.Message.Contains("Failed to link filesetid")) {
logger.LogError("Cannot link fileset {FilesetId} to volume {VolumeId}; fileset may be stale", filesetid, volumeid);
throw;
} Prevention
- Ensure the fileset row is committed in a prior transaction before calling LinkFilesetToVolumeAsync.
- Avoid concurrent delete operations that might remove the fileset between creation and linking.
- Pass only freshly created fileset IDs obtained from the same database connection context.
When it happens
Trigger: LinkFilesetToVolumeAsync is called with a (filesetid, volumeid) pair. It runs UPDATE Fileset SET VolumeID = @VolumeId WHERE ID = @FilesetId within transaction m_rtr and checks that exactly 1 row was affected. If filesetid was already deleted, never created, or the caller passed a stale ID, the count is 0 and the exception fires.
Common situations: Called during fileset-to-volume linking after uploading a new backup version or during repair. A stale or invalid filesetid -- e.g., referencing a fileset that a concurrent delete operation already removed -- is the most common cause. Can also occur if the fileset was created in a different transaction that was rolled back.
Related errors
- Start path not found: {startpath}
- KeepWebservicePasswordWithPassword
- SetInitPassword: child process exited with code " + rc
- InvalidAgentSettingsKey
- AgentSettingsKeyMissing
AI-assisted analysis of duplicati/duplicati@3f348be3e3 (2026-08-13).
Data as JSON: /api/errors/d7ae70e0e3471581.
Report an issue: GitHub.