{"record":{"id":"67adacb0fa54b5b8","repo":"duplicati/duplicati","slug":"backendtoolinvalidlocktimespan","errorCode":"BackendToolInvalidLockTimespan","errorMessage":"Invalid lock duration: {ex.Message}","messagePattern":"Invalid lock duration: (.+?)","errorType":"exception","errorClass":"UserInformationException","httpStatus":null,"severity":"error","filePath":"Duplicati/CommandLine/BackendTool/Program.cs","lineNumber":217,"sourceCode":"                    }\r\n                    else if (command == \"set-lock\")\r\n                    {\r\n                        if (args.Count < 4)\r\n                            throw new UserInformationException(\"SET-LOCK requires a filename and a lock duration argument\", \"BackendToolSetLockRequiresArguments\");\r\n                        if (args.Count > 4)\r\n                            throw new UserInformationException(string.Format(\"too many arguments: {0}\", string.Join(\",\", args)), \"BackendToolTooManyArguments\");\r\n\r\n                        if (backend is not ILockingBackend lockingBackend)\r\n                            throw new UserInformationException(\"Backend does not support object locking operations\", \"BackendToolObjectLockNotSupported\");\r\n\r\n                        TimeSpan lockDuration;\r\n                        try\r\n                        {\r\n                            lockDuration = Timeparser.ParseTimeSpan(args[3]);\r\n                        }\r\n                        catch (Exception ex)\r\n                        {\r\n                            throw new UserInformationException($\"Invalid lock duration: {ex.Message}\", \"BackendToolInvalidLockTimespan\");\r\n                        }\r\n\r\n                        if (lockDuration < TimeSpan.Zero)\r\n                            throw new UserInformationException(\"Lock duration must not be negative\", \"BackendToolNegativeLockTimespan\");\r\n\r\n                        var lockUntilUtc = DateTime.UtcNow.Add(lockDuration);\r\n                        lockingBackend.SetObjectLockUntilAsync(Path.GetFileName(args[2]), lockUntilUtc, CancellationToken.None).Await();\r\n\r\n                        return 0;\r\n                    }\r\n\r\n                    throw new Exception(\"Internal error\");\r\n                }\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"Command failed: \" + ex.Message);\r\n                if (debugoutput || !(ex is UserInformationException))\r","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/duplicati/duplicati/blob/3f348be3e33f5d72d414e3ad55839c2ba34dda67/Duplicati/CommandLine/BackendTool/Program.cs#L199-L235","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use the correct timespan format: a number followed by a unit — '30D' (days), '12h' (hours), '1W' (week), '15m' (minutes).","Check the wrapped exception message for the specific parse failure reason.","Refer to the help text: 'SET-LOCK requires a filename and a lock duration timespan (e.g. 30D or 12h)'"],"exampleFix":"// before\nbackendtool set-lock s3://user:pass@bucket/folder file.dblock \"30 days\"\n\n// after\nbackendtool set-lock s3://user:pass@bucket/folder file.dblock 30D","handlingStrategy":"validation","validationCode":"// Validate duration format before passing to set-lock:\nvar duration = args[3];\nif (!System.Text.RegularExpressions.Regex.IsMatch(duration, @\"^\\d+[smhdWMY]$\"))\n    throw new ArgumentException($\"Invalid duration format '{duration}'. Use format like '30D', '12h', '15m'.\");","typeGuard":null,"tryCatchPattern":"// Wrap the set-lock call to catch parse failures:\ntry\n{\n    backendtool set-lock <url> <file> <duration>\n}\ncatch (UserInformationException ex) when (ex.HelpID == \"BackendToolInvalidLockTimespan\")\n{\n    Console.WriteLine($\"Duration parse failed: {ex.Message}\");\n}","preventionTips":["Duration format is number + unit: s (seconds), m (minutes), h (hours), D (days), W (weeks), M (months), Y (years).","Always include a unit — bare numbers are rejected."],"tags":["cli","backendtool","object-lock","time-parsing","argument-validation"],"backgroundTag":null,"analyzedSha":"3f348be3e33f5d72d414e3ad55839c2ba34dda67","analyzedAt":"2026-08-13T16:48:27.008Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}