{"record":{"id":"d7f197cc945f719b","repo":"d2phap/ImageGlass","slug":"ige-metadata-too-large-contentlength-bytes","errorCode":null,"errorMessage":"IGE: Metadata too large: {contentLength} bytes.","messagePattern":"IGE: Metadata too large: (.+?) bytes\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"warning","filePath":"source/ImageGlass.Lib/Common/ServiceProviders/UpdateProvider.cs","lineNumber":168,"sourceCode":"    private static async Task<string?> FetchMetadataAsync(bool isScheduled, CancellationToken ct)\n    {\n        using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(ct);\n        timeoutCts.CancelAfter(UpdateConstants.MetadataTimeout);\n\n        using var request = new HttpRequestMessage(HttpMethod.Get, UpdateConstants.MetadataUrl);\n\n        // set per request: the value varies per check, so it cannot live on the shared client\n        request.Headers.UserAgent.ParseAdd(UsageStatsAgent.Build(isScheduled));\n\n        using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, timeoutCts.Token)\n            .ConfigureAwait(false);\n        response.EnsureSuccessStatusCode();\n\n        // enforce size limit\n        var contentLength = response.Content.Headers.ContentLength ?? 0;\n        if (contentLength > UpdateConstants.MaxMetadataSize)\n        {\n            throw new InvalidOperationException($\"IGE: Metadata too large: {contentLength} bytes.\");\n        }\n\n        var json = await response.Content.ReadAsStringAsync(timeoutCts.Token).ConfigureAwait(false);\n        if (json.Length > UpdateConstants.MaxMetadataSize)\n        {\n            throw new InvalidOperationException($\"IGE: Metadata body exceeded limit: {json.Length} chars.\");\n        }\n\n        return json;\n    }\n\n\n    /// <summary>\n    /// Parses the last check time from <see cref=\"Core.Config.AutoUpdate\"/>.\n    /// </summary>\n    private static DateTime ParseLastCheckTime()\n    {\n        var value = Core.Config.AutoUpdate;","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/d2phap/ImageGlass/blob/4a3c4feceffc5a8bb5e56ba836509634aaae47a9/source/ImageGlass.Lib/Common/ServiceProviders/UpdateProvider.cs#L150-L186","documentation":"Thrown by UpdateProvider when fetching update metadata: the HTTP response's Content-Length header exceeds UpdateConstants.MaxMetadataSize (1 MiB, defined in Update/UpdateConstants.cs:44). The size limit exists because update metadata is a small JSON document, so anything larger is either a misconfigured endpoint or a malicious/broken payload that should not be fully buffered into memory.","triggerScenarios":"Produced by UpdateProvider's metadata fetch path: after response.EnsureSuccessStatusCode() the code reads response.Content.Headers.ContentLength and throws when that value > 1 * 1024 * 1024. Triggers when the server advertises a large body for the update JSON URL, or when a CDN/reverse proxy in front of the real endpoint serves the wrong (oversized) resource.","commonSituations":"Update endpoint behind a CDN that returns an HTML error page (which can be large) instead of JSON; a typo'd/migrated update URL now pointing at a HTML landing page; a malicious mirror replacing the manifest with a large file; corporate proxy injecting a large block page; a staging server accidentally returning a debug bundle.","solutions":["Verify the configured update metadata URL points at the real ImageGlass update manifest and not a HTML page or error payload.","If you self-host the manifest, ensure the server returns only the JSON document and that Content-Length is under 1 MiB; remove any injected wrapping page.","Catch InvalidOperationException around the update check and surface a user-facing 'update check failed' message rather than crashing; retry on the next scheduled check.","If the limit is genuinely too small for your manifest, raise UpdateConstants.MaxMetadataSize in Update/UpdateConstants.cs:44 (but 1 MiB is already very large for JSON metadata)."],"exampleFix":"// before\nusing var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, timeoutCts.Token);\nresponse.EnsureSuccessStatusCode();\nvar contentLength = response.Content.Headers.ContentLength ?? 0;\nif (contentLength > UpdateConstants.MaxMetadataSize) throw new InvalidOperationException(...);\n\n// after — reject non-JSON early so a CDN HTML page never reaches the size check\nusing var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, timeoutCts.Token);\nresponse.EnsureSuccessStatusCode();\nvar ct = response.Content.Headers.ContentType?.MediaType;\nif (!string.Equals(ct, \"application/json\", StringComparison.OrdinalIgnoreCase))\n    throw new InvalidOperationException(\"IGE: Update endpoint did not return JSON.\");\nvar contentLength = response.Content.Headers.ContentLength ?? 0;\nif (contentLength > UpdateConstants.MaxMetadataSize) throw new InvalidOperationException(...);","handlingStrategy":"validation","validationCode":"// Before calling the update-check API, validate the endpoint and request shape.\nif (string.IsNullOrWhiteSpace(updateUrl) || !Uri.TryCreate(updateUrl, UriKind.Absolute, out var uri) || uri.Scheme != Uri.UriSchemeHttps)\n    return UpdateCheckResult.Skipped(\"Invalid update URL\");\n\n// After the response arrives, check Content-Type and Content-Length before buffering.\nvar media = response.Content.Headers.ContentType?.MediaType;\nif (!string.Equals(media, \"application/json\", StringComparison.OrdinalIgnoreCase))\n    return UpdateCheckResult.Skipped($\"Unexpected content type {media}\");\nvar len = response.Content.Headers.ContentLength ?? -1;\nif (len > UpdateConstants.MaxMetadataSize)\n    return UpdateCheckResult.Skipped($\"Metadata too large: {len} bytes\");","typeGuard":null,"tryCatchPattern":"try { var json = await updateProvider.FetchMetadataAsync(token); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Metadata too large\"))\n{ _log.Warn($\"Update metadata oversize, skipping check: {ex.Message}\"); return; }","preventionTips":["Always validate the update URL is HTTPS and points at the canonical ImageGlass manifest.","Inspect Content-Type before reading the body so a CDN error page never reaches the size check.","Run update checks on a schedule with a timeout so a stuck/oversized response cannot hang the app.","Log the failing URL and Content-Length on this error so a misconfigured endpoint is visible immediately."],"tags":["network","http","update","config","size-limit"],"backgroundTag":null,"analyzedSha":"4a3c4feceffc5a8bb5e56ba836509634aaae47a9","analyzedAt":"2026-08-13T16:58:15.523Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}