{"record":{"id":"1ee8f52057a7ea14","repo":"JosefNemec/Playnite","slug":"no-profile-provided","errorCode":null,"errorMessage":"No profile provided.","messagePattern":"No profile provided\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"source/Playnite/Emulators/Scanner.cs","lineNumber":630,"sourceCode":"                    mergeRelatedFiles,\r\n                    fileScanCallback);\r\n            }\r\n        }\r\n\r\n        private List<ScannedGame> ScanDirectory(\r\n            string directory,\r\n            Emulator emulator,\r\n            CustomEmulatorProfile profile,\r\n            CancellationToken cancelToken,\r\n            string crcExludePatterns,\r\n            bool scanSubfolders,\r\n            bool scanArchives,\r\n            bool mergeRelatedFiles,\r\n            Action<string> fileScanCallback = null)\r\n        {\r\n            if (profile == null)\r\n            {\r\n                throw new Exception($\"No profile provided.\");\r\n            }\r\n\r\n            if (!profile.ImageExtensions.HasItems())\r\n            {\r\n                return new List<ScannedGame>();\r\n            }\r\n\r\n            var platforms = profile.Platforms?.Select(a => database.Platforms[a]?.SpecificationId).Where(a => !a.IsNullOrEmpty()).ToList();\r\n            return ScanDirectory(\r\n                directory,\r\n                profile.ImageExtensions.Select(a => a.Trim()).ToList(),\r\n                platforms,\r\n                cancelToken,\r\n                crcExludePatterns,\r\n                scanSubfolders,\r\n                scanArchives,\r\n                mergeRelatedFiles,\r\n                fileScanCallback);\r","sourceCodeStart":612,"sourceCodeEnd":648,"githubUrl":"https://github.com/JosefNemec/Playnite/blob/5911f4e964e628aa7a69c2030ab35101afa63067/source/Playnite/Emulators/Scanner.cs#L612-L648","documentation":"Thrown by the ScanDirectory overload accepting a CustomEmulatorProfile when the caller passes null. It is a null-argument guard: the method dereferences profile.ImageExtensions and profile.Platforms immediately after, so a null profile must be rejected before use.","triggerScenarios":"Calling ScanDirectory(directory, emulator, profile, ...) with profile == null. Typically the result of a lookup like emulator.CustomProfiles?.FirstOrDefault(...) returning null and being passed through without a check.","commonSituations":"A scan configuration references a custom profile id that no longer exists on the emulator; a code path that creates a scanner without resolving its profile; UI flow that allows starting a scan before a profile is selected.","solutions":["Resolve the CustomEmulatorProfile by id before calling and skip/handle if null rather than passing null.","Add a null-check at the call site and log a warning instead of propagating null into ScanDirectory.","Use ArgumentNullException to make the contract explicit."],"exampleFix":"// before\nif (profile == null) { throw new Exception($\"No profile provided.\"); }\n\n// after\nif (profile == null) { throw new ArgumentNullException(nameof(profile), \"A CustomEmulatorProfile must be supplied to scan.\"); }","handlingStrategy":"validation","validationCode":"// Resolve and null-check the custom profile before scanning.\nvar profile = emulator.CustomProfiles?.FirstOrDefault(p => p.Id == scanner.EmulatorProfileId);\nif (profile == null) { logger.Warn(\"Custom profile missing; skip scan.\"); return; }","typeGuard":"static bool HasCustomProfile(Emulator emu, string id) =>\n    emu.CustomProfiles?.Any(p => p.Id == id) == true;","tryCatchPattern":null,"preventionTips":["Never pass unresolved profile lookups directly into ScanDirectory.","Use ArgumentNullException for null profile arguments to make contracts explicit.","In the scan UI, disable the scan button until a profile is selected."],"tags":["emulator","scanner","null-argument","validation"],"backgroundTag":null,"analyzedSha":"5911f4e964e628aa7a69c2030ab35101afa63067","analyzedAt":"2026-08-13T17:38:25.713Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}