{"record":{"id":"005353e0a5b9eb2e","repo":"BeyondDimension/SteamTools","slug":"pin-code-cannot-be-empty","errorCode":null,"errorMessage":"PIN CODE cannot be empty","messagePattern":"PIN CODE cannot be empty","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"warning","filePath":"src/BD.WTTS.Client.Plugins.SteamIdleCard/UI/ViewModels/IdleCardPageViewModel.cs","lineNumber":408,"sourceCode":"            HttpStatusCode status;\n\n        GetBadges:\n            var steam_id = SteamLoginState.SteamId.ToString();\n            (UserIdleInfo, badges, status) = await IdleCard.GetBadgesAsync(steam_id, true);\n            if (status == HttpStatusCode.Forbidden)\n            {\n                var result = await TextBoxWindowViewModel.ShowDialogAsync(new TextBoxWindowViewModel\n                {\n                    Title = Strings.Idle_NeedParentalPIN,\n                    Placeholder = \"PIN CODE\",\n                    InputType = TextBoxWindowViewModel.TextBoxInputType.Password,\n                });\n                if (!string.IsNullOrEmpty(result))\n                {\n                    await steamSession.UnlockParental(steam_id, result);\n                    goto GetBadges;\n                }\n                throw new ArgumentNullException(Strings.Idle_PIN_NotBeNull);\n            }\n            else if (status != HttpStatusCode.OK)\n                throw new HttpRequestException($\"{Strings.Idle_GetBadgesError} status code: {status}\");\n            goto HandleBadges;\n\n        HandleBadges:\n            Badges.Clear();\n            Badges.Add(badges!);\n            //await RefreshPrivateGameAppIds(steam_id);\n            TotalCardsRemaining = 0;\n            TotalCardsAvgPrice = 0;\n\n            badges = badges!.Where(w => w.CardsRemaining != 0);\n\n            foreach (var badge in badges)\n            {\n                if (IsExcludedApp(badge.AppId))\n                    continue;","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/BeyondDimension/SteamTools/blob/c16ffa08e03b192d23ada290c4969e77f9201f3d/src/BD.WTTS.Client.Plugins.SteamIdleCard/UI/ViewModels/IdleCardPageViewModel.cs#L390-L426","documentation":"Thrown (as ArgumentNullException) when the Steam badge fetch returns a parental-lock status and the user dismisses/leaves empty the PIN dialog. The code prompts for a PIN via ShowDialogAsync; if the result is null/empty it throws ArgumentNullException with the localized 'PIN must not be null' message instead of attempting UnlockParental with a blank PIN.","triggerScenarios":"Fetching badges for a Steam account with parental controls enabled; the returned status indicates parental lock; the user closes the PIN dialog or submits an empty string, so result is null/empty.","commonSituations":"User clicked Cancel/Close on the PIN prompt; user typed nothing and pressed OK; dialog returned null due to a UI issue; account has parental lock the user cannot satisfy.","solutions":["Re-enter a valid parental PIN when prompted instead of dismissing the dialog.","Disable parental controls on the Steam account (or have the parent remove the PIN) then retry.","Catch the exception and re-prompt the user rather than aborting the whole badge fetch.","Throw a domain-specific exception (not ArgumentNullException) so callers can distinguish user-cancel from a real null bug."],"exampleFix":"// before\nif (!string.IsNullOrEmpty(result))\n{\n    await steamSession.UnlockParental(steam_id, result);\n    goto GetBadges;\n}\nthrow new ArgumentNullException(Strings.Idle_PIN_NotBeNull);\n\n// after: re-prompt or throw a user-facing exception\nif (!string.IsNullOrEmpty(result))\n{\n    await steamSession.UnlockParental(steam_id, result);\n    goto GetBadges;\n}\nthrow new OperationCanceledException(Strings.Idle_PIN_NotBeNull);","handlingStrategy":"validation","validationCode":"// Treat an empty PIN as user-cancel and handle gracefully instead of throwing.\nif (string.IsNullOrEmpty(result))\n{\n    // Re-prompt or abort the badge fetch with a clear, non-exception flow.\n    StatusMessage = Strings.Idle_PIN_NotBeNull;\n    return; // or loop the dialog a bounded number of times\n}\nawait steamSession.UnlockParental(steam_id, result);","typeGuard":"bool IsValidPin(string? pin) => !string.IsNullOrWhiteSpace(pin) && pin.All(char.IsDigit);","tryCatchPattern":"// Catch the misplaced ArgumentNullException so the app does not crash on cancel.\ntry { await FetchBadgesAsync(); }\ncatch (ArgumentNullException ex) when (ex.Message == Strings.Idle_PIN_NotBeNull)\n{\n    Log.Information(\"User cancelled the parental PIN prompt.\");\n    StatusMessage = Strings.Idle_PIN_NotBeNull;\n}","preventionTips":["Distinguish 'user cancelled' (empty result) from a real error; do not throw ArgumentNullException for user input.","Bound the number of PIN re-prompts to avoid an infinite loop.","Throw a domain exception (e.g. OperationCanceledException) for cancel, not ArgumentNullException.","Disable the idle feature gracefully when parental controls are active and unsatisfied."],"tags":["steam","idle-card","validation","user-input"],"backgroundTag":null,"analyzedSha":"c16ffa08e03b192d23ada290c4969e77f9201f3d","analyzedAt":"2026-08-13T11:52:20.410Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}