{"record":{"id":"01d7fc0a52280f3a","repo":"glanceapp/glance","slug":"w-missing-d-rss-feeds","errorCode":null,"errorMessage":"%w: missing %d RSS feeds","messagePattern":"%w: missing (.+?) RSS feeds","errorType":"exception","errorClass":"errPartialContent","httpStatus":null,"severity":"warning","filePath":"internal/glance/widget-rss.go","lineNumber":186,"sourceCode":"\t\t\tslog.Error(\"Failed to get RSS feed\", \"url\", requests[i].URL, \"error\", errs[i])\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, item := range feeds[i] {\n\t\t\tif _, exists := seen[item.Link]; exists {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tentries = append(entries, item)\n\t\t\tseen[item.Link] = struct{}{}\n\t\t}\n\t}\n\n\tif failed == len(requests) {\n\t\treturn nil, errNoContent\n\t}\n\n\tif failed > 0 {\n\t\treturn entries, fmt.Errorf(\"%w: missing %d RSS feeds\", errPartialContent, failed)\n\t}\n\n\treturn entries, nil\n}\n\nfunc (widget *rssWidget) fetchItemsFromFeedTask(request rssFeedRequest) ([]rssFeedItem, error) {\n\treq, err := http.NewRequest(\"GET\", request.URL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq.Header.Add(\"User-Agent\", glanceUserAgentString)\n\n\twidget.cachedFeedsMutex.Lock()\n\tcache, isCached := widget.cachedFeeds[request.URL]\n\tif isCached {\n\t\tif cache.etag != \"\" {\n\t\t\treq.Header.Add(\"If-None-Match\", cache.etag)","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-rss.go#L168-L204","documentation":"Returned by rssWidget.fetchItemsFromFeeds (internal/glance/widget-rss.go:186) when at least one but not all feeds failed (failed > 0 && failed < len(requests)). Entries from the healthy feeds are still returned with errPartialContent; each failing feed is logged ('Failed to get RSS feed' with URL and error) and skipped. Only when every feed fails does it return bare errNoContent instead.","triggerScenarios":"A subset of feed URLs erroring: 404/Gone after a site moved its feed path, DNS failure for one domain, TLS certificate expiry, a 403 from a feed behind Cloudflare, or a feed that changed to a format gofeed cannot parse — while at least one other feed in the widget still works.","commonSituations":"Aggregator widgets listing many feeds where one site redesigned; expired certs on small blogs; feeds that now require user-agent headers; transient network blips on refresh.","solutions":["Check Glance logs for the exact failing URL and cause ('Failed to get RSS feed')","Update or remove dead feed URLs from the widget config","Verify the feed URL with curl -L and follow redirects to the current feed location","For transient failures, rely on the next refresh — partial content still renders"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"items, err := widget.fetchItemsFromFeeds()\nif err != nil && errors.Is(err, errPartialContent) {\n    // render `items` from healthy feeds; check logs for failing URLs\n}","preventionTips":["Audit feed URLs when sites redesign","Follow permanent redirects to new feed locations","Accept partial rendering — only total failure empties the widget"],"tags":["rss","partial-content","feeds"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}