{"record":{"id":"8b9142d35f85080d","repo":"beeradmoore/dlss-swapper","slug":"could-not-deserialize-gogembedfilteredresponse-for-url-url","errorCode":null,"errorMessage":"Could not deserialize GOGEmbedFilteredResponse for url, {url}","messagePattern":"Could not deserialize GOGEmbedFilteredResponse for url, (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/Data/GOG/GOGGame.cs","lineNumber":123,"sourceCode":"        }\n\n\n        // If catalog failed fall back to embeded search.\n        /*\n        try\n        {\n            var url = \"https://embed.gog.com/games/ajax/filtered?mediaType=game&search=\" + Uri.EscapeDataString(Title);\n\n            var fileDownloader = new FileDownloader(url);\n            using (var memoryStream = new MemoryStream())\n            {\n                await fileDownloader.DownloadFileToStreamAsync(memoryStream);\n                memoryStream.Position = 0;\n\n                var embedFilteredResponse = JsonSerializer.Deserialize(memoryStream, SourceGenerationContext.Default.GOGEmbedFilteredResponse);\n                if (embedFilteredResponse is null)\n                {\n                    throw new Exception($\"Could not deserialize GOGEmbedFilteredResponse for url, {url}\");\n                }\n\n                if (embedFilteredResponse.Products.Length == 0)\n                {\n                    throw new Exception($\"Could not find any GOGEmbedFilteredProducts for url, {url}\");\n                }\n\n                foreach (var product in embedFilteredResponse.Products)\n                {\n                    if (product.Id.ToString().Equals(PlatformId, StringComparison.OrdinalIgnoreCase) == false)\n                    {\n                        continue;\n                    }\n\n                    if (string.IsNullOrWhiteSpace(product.BoxImage) == false)\n                    {\n                        await DownloadCoverAsync($\"https:{product.BoxImage}_glx_vertical_cover.webp\").ConfigureAwait(false);\n                        return;","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/beeradmoore/dlss-swapper/blob/ab9b1e2d4bb04187c48fe58eeea06c2b0ea71fbb/src/Data/GOG/GOGGame.cs#L105-L141","documentation":"UpdateCacheImageAsync also fetches a GOG 'embed filtered' products endpoint and deserializes it into GOGEmbedFilteredResponse; a null result throws this error. Null indicates an empty body or JSON that does not match the GOGEmbedFilteredResponse contract, blocking resolution of embed product data for the cache image.","triggerScenarios":"Calling UpdateCacheImageAsync when the embed-filtered endpoint returns an empty body, HTML error/consent page, or JSON incompatible with the source-generated GOGEmbedFilteredResponse deserializer.","commonSituations":"GOG endpoint shape changed after an API update; bot-protection/Cloudflare page returned instead of JSON; wrong game URL producing 404; transient GOG outage or rate limiting.","solutions":["Curl the embed-filtered URL and confirm it returns the expected JSON shape","Retry after transient GOG failures or rate limiting","Regenerate/update the deserialization contract if GOG changed the response schema","Log the raw response body when deserialization fails to spot HTML/error pages"],"exampleFix":"// before\nvar embedFilteredResponse = JsonSerializer.Deserialize(memoryStream, SourceGenerationContext.Default.GOGEmbedFilteredResponse);\nif (embedFilteredResponse is null)\n{\n    throw new Exception($\"Could not deserialize GOGEmbedFilteredResponse for url, {url}\");\n}\n// after\nembedFilteredResponse = JsonSerializer.Deserialize(memoryStream, SourceGenerationContext.Default.GOGEmbedFilteredResponse);\nif (embedFilteredResponse is null)\n{\n    throw new Exception($\"Could not deserialize GOGEmbedFilteredResponse for url, {url}. Body length: {memoryStream.Length}\");\n}","handlingStrategy":"try-catch","validationCode":"// preflight the embed-filtered URL\nusing var probe = await httpClient.GetAsync(url);\nvar body = await probe.Content.ReadAsStringAsync();\nif (body.Contains(\"<html\", StringComparison.OrdinalIgnoreCase))\n    throw new InvalidOperationException($\"GOG embed endpoint returned HTML for {url} (bot protection or error page).\");","typeGuard":"static bool LooksLikeEmbedFiltered(string json) => json.TrimStart().StartsWith(\"{\") && json.Contains(\"products\", StringComparison.OrdinalIgnoreCase);","tryCatchPattern":"try\n{\n    await gogGame.UpdateCacheImageAsync();\n}\ncatch (Exception ex) when (ex.Message.Contains(\"Could not deserialize GOGEmbedFilteredResponse\"))\n{\n    logger.LogWarning(ex, \"GOG embed response unusable for {Url}; skipping cache image.\", url);\n}","preventionTips":["Detect HTML/bot-protection responses before JSON parsing","Retry with backoff on rate-limited embed requests","Update the GOGEmbedFilteredResponse contract when the API evolves","Log response status + first bytes on deserialization failure"],"tags":["gog","json","deserialization","http"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"ab9b1e2d4bb04187c48fe58eeea06c2b0ea71fbb","analyzedAt":"2026-09-15T05:25:32.979Z","contentChangedAt":"2026-09-15T05:25:32.979Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}