{"record":{"id":"4b6e6efd15842934","repo":"Devolutions/UniGetUI","slug":"taillines-must-be-greater-than-or-equal-to-zero","errorCode":null,"errorMessage":"tailLines must be greater than or equal to zero.","messagePattern":"tailLines must be greater than or equal to zero\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"warning","filePath":"src/UniGetUI.Interface.IpcApi/IpcOperationApi.cs","lineNumber":184,"sourceCode":"            CanCancel = info.CanCancel,\n            CanForget = info.CanForget,\n            AvailableQueueActions = info.AvailableQueueActions,\n            AvailableRetryModes = info.AvailableRetryModes,\n            Package = info.Package,\n            ManagerName = info.ManagerName,\n            SourceName = info.SourceName,\n            Output = tracked.GetOutputSnapshot(),\n        };\n    }\n\n    public static IpcOperationOutputResult GetOperationOutput(\n        string operationId,\n        int? tailLines = null\n    )\n    {\n        if (tailLines.HasValue && tailLines.Value < 0)\n        {\n            throw new InvalidOperationException(\"tailLines must be greater than or equal to zero.\");\n        }\n\n        var tracked = GetTrackedOperation(operationId);\n        return new IpcOperationOutputResult\n        {\n            OperationId = tracked.Operation.Metadata.Identifier,\n            LineCount = tracked.GetOutputCount(),\n            Output = tracked.GetOutputSnapshot(tailLines),\n        };\n    }\n\n    public static IpcCommandResult CancelOperation(string operationId)\n    {\n        var tracked = GetTrackedOperation(operationId);\n        if (!IsActive(tracked.Operation.Status))\n        {\n            throw new InvalidOperationException(\n                \"Only queued or running operations can be canceled.\"","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/Devolutions/UniGetUI/blob/9b1d7d0eab91620fc15c86b36676532095936ae3/src/UniGetUI.Interface.IpcApi/IpcOperationApi.cs#L166-L202","documentation":"Thrown by GetOperationOutput when the optional tailLines parameter is provided but is negative (less than zero). tailLines controls how many trailing output lines to return; zero means return all lines (the snapshot method treats <=0 as 'all'), while negative is rejected as invalid input.","triggerScenarios":"Calling GetOperationOutput(operationId, tailLines) where tailLines is a negative integer. The parameter is nullable int, so null (omit) is valid and means 'all lines'. A value of 0 is valid and also returns all lines per the GetOutputSnapshot logic.","commonSituations":"IPC client passes -1 as a 'give me everything' sentinel (should use null or 0 instead). Arithmetic on line counts produces a negative value when the operation has no output yet. Misunderstanding the parameter semantics.","solutions":["Pass null or omit tailLines entirely to get all output lines.","Pass 0 or a positive integer to limit the tail.","Ensure any computed tailLines value is clamped to >= 0 before calling."],"exampleFix":"// before\nvar result = IpcOperationApi.GetOperationOutput(opId, tailLines: lineCount - 10);\n// after — guard against negative\nvar tail = Math.Max(0, lineCount - 10);\nvar result = IpcOperationApi.GetOperationOutput(opId, tailLines: tail == 0 ? null : tail);","handlingStrategy":"validation","validationCode":"if (tailLines.HasValue && tailLines.Value < 0)\n    throw new ArgumentOutOfRangeException(nameof(tailLines), \"Must be >= 0.\");\n// Clamp or convert to null for 'all lines'\ntailLines = tailLines.HasValue && tailLines.Value <= 0 ? null : tailLines;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use null or omit tailLines for all output lines.","Use 0 or positive for tail-only output.","Clamp computed values to >= 0 before passing."],"tags":["operations","ipc","validation","parameters"],"backgroundTag":null,"analyzedSha":"9b1d7d0eab91620fc15c86b36676532095936ae3","analyzedAt":"2026-08-13T12:19:18.278Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}