beeradmoore/dlss-swapper · error · Exception
Could not deserialize GOGEmbedFilteredResponse for url
Error message
Could not deserialize GOGEmbedFilteredResponse for url, {url} What it means
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.
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
Example fix
// before
var embedFilteredResponse = JsonSerializer.Deserialize(memoryStream, SourceGenerationContext.Default.GOGEmbedFilteredResponse);
if (embedFilteredResponse is null)
{
throw new Exception($"Could not deserialize GOGEmbedFilteredResponse for url, {url}");
}
// after
embedFilteredResponse = JsonSerializer.Deserialize(memoryStream, SourceGenerationContext.Default.GOGEmbedFilteredResponse);
if (embedFilteredResponse is null)
{
throw new Exception($"Could not deserialize GOGEmbedFilteredResponse for url, {url}. Body length: {memoryStream.Length}");
} Defensive patterns
Strategy: try-catch
Validate before calling
// preflight the embed-filtered URL
using var probe = await httpClient.GetAsync(url);
var body = await probe.Content.ReadAsStringAsync();
if (body.Contains("<html", StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException($"GOG embed endpoint returned HTML for {url} (bot protection or error page)."); Type guard
static bool LooksLikeEmbedFiltered(string json) => json.TrimStart().StartsWith("{") && json.Contains("products", StringComparison.OrdinalIgnoreCase); Try / catch
try
{
await gogGame.UpdateCacheImageAsync();
}
catch (Exception ex) when (ex.Message.Contains("Could not deserialize GOGEmbedFilteredResponse"))
{
logger.LogWarning(ex, "GOG embed response unusable for {Url}; skipping cache image.", url);
} Prevention
- 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
When it happens
Trigger: Calling UpdateCacheImageAsync when the embed-filtered endpoint returns an empty body, HTML error/consent page, or JSON incompatible with the source-generated GOGEmbedFilteredResponse deserializer.
Common situations: 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.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- Could not deserialize GOGCatalogResponse for url
- Could not deserialize manifest.json.
- Could not find any GOGEmbedFilteredProducts for url
- Could not load GitHub release data.
- Could not download file.
AI-assisted analysis of beeradmoore/dlss-swapper@ab9b1e2d4b (2026-09-15).
Data as JSON: /api/errors/8b9142d35f85080d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Data/GOG/GOGGame.cs:123
}
// If catalog failed fall back to embeded search.
/*
try
{
var url = "https://embed.gog.com/games/ajax/filtered?mediaType=game&search=" + Uri.EscapeDataString(Title);
var fileDownloader = new FileDownloader(url);
using (var memoryStream = new MemoryStream())
{
await fileDownloader.DownloadFileToStreamAsync(memoryStream);
memoryStream.Position = 0;
var embedFilteredResponse = JsonSerializer.Deserialize(memoryStream, SourceGenerationContext.Default.GOGEmbedFilteredResponse);
if (embedFilteredResponse is null)
{
throw new Exception($"Could not deserialize GOGEmbedFilteredResponse for url, {url}");
}
if (embedFilteredResponse.Products.Length == 0)
{
throw new Exception($"Could not find any GOGEmbedFilteredProducts for url, {url}");
}
foreach (var product in embedFilteredResponse.Products)
{
if (product.Id.ToString().Equals(PlatformId, StringComparison.OrdinalIgnoreCase) == false)
{
continue;
}
if (string.IsNullOrWhiteSpace(product.BoxImage) == false)
{
await DownloadCoverAsync($"https:{product.BoxImage}_glx_vertical_cover.webp").ConfigureAwait(false);
return;View on GitHub (pinned to ab9b1e2d4b)