{"record":{"id":"a5c084ec13434cda","repo":"Devolutions/UniGetUI","slug":"unsupported-retry-mode-retrymode","errorCode":null,"errorMessage":"Unsupported retry mode \"{retryMode}\".","messagePattern":"Unsupported retry mode \"(.+?)\"\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":400,"severity":"error","filePath":"src/UniGetUI.Interface.IpcApi/IpcOperationApi.cs","lineNumber":436,"sourceCode":"        }\n\n        return retryModes;\n    }\n\n    private static string NormalizeRetryMode(string? retryMode)\n    {\n        if (string.IsNullOrWhiteSpace(retryMode))\n        {\n            return AbstractOperation.RetryMode.Retry;\n        }\n\n        return retryMode.Trim().ToLowerInvariant() switch\n        {\n            \"retry\" => AbstractOperation.RetryMode.Retry,\n            \"retry-as-admin\" => AbstractOperation.RetryMode.Retry_AsAdmin,\n            \"retry-interactive\" => AbstractOperation.RetryMode.Retry_Interactive,\n            \"retry-no-hash-check\" => AbstractOperation.RetryMode.Retry_SkipIntegrity,\n            _ => throw new InvalidOperationException(\n                $\"Unsupported retry mode \\\"{retryMode}\\\".\"\n            ),\n        };\n    }\n\n    private static string ToRetryModeName(string retryMode)\n    {\n        return retryMode switch\n        {\n            var mode when mode == AbstractOperation.RetryMode.Retry => \"retry\",\n            var mode when mode == AbstractOperation.RetryMode.Retry_AsAdmin => \"retry-as-admin\",\n            var mode when mode == AbstractOperation.RetryMode.Retry_Interactive\n                => \"retry-interactive\",\n            var mode when mode == AbstractOperation.RetryMode.Retry_SkipIntegrity\n                => \"retry-no-hash-check\",\n            _ => retryMode,\n        };\n    }","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/Devolutions/UniGetUI/blob/9b1d7d0eab91620fc15c86b36676532095936ae3/src/UniGetUI.Interface.IpcApi/IpcOperationApi.cs#L418-L454","documentation":"NormalizeRetryMode throws when the retryMode string (matched case-insensitively, trimmed) is not one of: retry, retry-as-admin, retry-interactive, retry-no-hash-check. A null/empty mode is permitted and defaults to plain Retry; any other spelling is rejected.","triggerScenarios":"Calling RetryOperation with a value like \"admin\", \"retry-admin\", \"force\", or \"as-admin\".","commonSituations":"Client built the mode from free-form user input; shorthand used in UI leaked into the API; cross-version rename of a token.","solutions":["Restrict retryMode to the four literal tokens","Drive the value from the AvailableRetryModes list returned on IpcOperationInfo rather than hardcoding","Whitelist-validate client-side before the call"],"exampleFix":"// before\nIpcOperationApi.RetryOperation(opId, mode: \"admin\");\n// after\nvar allowed = info.AvailableRetryModes; // [\"retry\",\"retry-as-admin\",...]\nvar mode = allowed.Contains(userChoice, StringComparer.OrdinalIgnoreCase) ? userChoice : \"retry\";\nIpcOperationApi.RetryOperation(opId, mode: mode);","handlingStrategy":"validation","validationCode":"static readonly HashSet<string> RetryModes = new(StringComparer.OrdinalIgnoreCase)\n    { \"retry\", \"retry-as-admin\", \"retry-interactive\", \"retry-no-hash-check\" };\n\nif (!RetryModes.Contains(retryMode))\n    throw new ArgumentException($\"Bad retry mode: {retryMode}\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use AvailableRetryModes from the operation payload, not a literal","Centralize the allowed-token list in one client constant"],"tags":["ipc","retry","enum-validation"],"backgroundTag":null,"analyzedSha":"9b1d7d0eab91620fc15c86b36676532095936ae3","analyzedAt":"2026-08-13T12:19:18.278Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}