duplicati/duplicati · error · UserInformationException

BackendToolInvalidLockTimespan

BackendToolInvalidLockTimespan

Error message

Invalid lock duration: {ex.Message}

What it means

Thrown when the lock-duration string passed to set-lock cannot be parsed by Timeparser.ParseTimeSpan. The duration argument (args[3]) must be a valid Duplicati timespan expression (e.g., '30D', '12h', '1W'). The original parse exception message is wrapped into this UserInformationException.

Source

Thrown at Duplicati/CommandLine/BackendTool/Program.cs:217

                    }
                    else if (command == "set-lock")
                    {
                        if (args.Count < 4)
                            throw new UserInformationException("SET-LOCK requires a filename and a lock duration argument", "BackendToolSetLockRequiresArguments");
                        if (args.Count > 4)
                            throw new UserInformationException(string.Format("too many arguments: {0}", string.Join(",", args)), "BackendToolTooManyArguments");

                        if (backend is not ILockingBackend lockingBackend)
                            throw new UserInformationException("Backend does not support object locking operations", "BackendToolObjectLockNotSupported");

                        TimeSpan lockDuration;
                        try
                        {
                            lockDuration = Timeparser.ParseTimeSpan(args[3]);
                        }
                        catch (Exception ex)
                        {
                            throw new UserInformationException($"Invalid lock duration: {ex.Message}", "BackendToolInvalidLockTimespan");
                        }

                        if (lockDuration < TimeSpan.Zero)
                            throw new UserInformationException("Lock duration must not be negative", "BackendToolNegativeLockTimespan");

                        var lockUntilUtc = DateTime.UtcNow.Add(lockDuration);
                        lockingBackend.SetObjectLockUntilAsync(Path.GetFileName(args[2]), lockUntilUtc, CancellationToken.None).Await();

                        return 0;
                    }

                    throw new Exception("Internal error");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Command failed: " + ex.Message);
                if (debugoutput || !(ex is UserInformationException))

View on GitHub (pinned to 3f348be3e3)

Solutions

  1. Use the correct timespan format: a number followed by a unit — '30D' (days), '12h' (hours), '1W' (week), '15m' (minutes).
  2. Check the wrapped exception message for the specific parse failure reason.
  3. Refer to the help text: 'SET-LOCK requires a filename and a lock duration timespan (e.g. 30D or 12h)'

Example fix

// before
backendtool set-lock s3://user:pass@bucket/folder file.dblock "30 days"

// after
backendtool set-lock s3://user:pass@bucket/folder file.dblock 30D
Defensive patterns

Strategy: validation

Validate before calling

// Validate duration format before passing to set-lock:
var duration = args[3];
if (!System.Text.RegularExpressions.Regex.IsMatch(duration, @"^\d+[smhdWMY]$"))
    throw new ArgumentException($"Invalid duration format '{duration}'. Use format like '30D', '12h', '15m'.");

Try / catch

// Wrap the set-lock call to catch parse failures:
try
{
    backendtool set-lock <url> <file> <duration>
}
catch (UserInformationException ex) when (ex.HelpID == "BackendToolInvalidLockTimespan")
{
    Console.WriteLine($"Duration parse failed: {ex.Message}");
}

Prevention

When it happens

Trigger: Passing a malformed duration string such as 'thirty days', '30', 'abc', or an empty string as args[3] to set-lock. Timeparser.ParseTimeSpan expects formats like '1D', '2h', '30m', '1W', etc.

Common situations: User passes a plain number without a unit ('30' instead of '30D'), uses full English words instead of the abbreviation format, or passes a negative value that parses but is separately caught by the negative-check.

Related errors


AI-assisted analysis of duplicati/duplicati@3f348be3e3 (2026-08-13). Data as JSON: /api/errors/67adacb0fa54b5b8. Report an issue: GitHub.