{"record":{"id":"d6ad2ceb607f8164","repo":"glanceapp/glance","slug":"w-failed-to-fetch-d-channels","errorCode":null,"errorMessage":"%w: failed to fetch %d channels","messagePattern":"%w: failed to fetch (.+?) channels","errorType":"exception","errorClass":"errPartialContent","httpStatus":null,"severity":"warning","filePath":"internal/glance/widget-twitch-channels.go","lineNumber":234,"sourceCode":"\n\tvar failed int\n\n\tfor i := range channels {\n\t\tif errs[i] != nil {\n\t\t\tfailed++\n\t\t\tslog.Error(\"Failed to fetch Twitch channel\", \"channel\", channelLogins[i], \"error\", errs[i])\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, channels[i])\n\t}\n\n\tif failed == len(channelLogins) {\n\t\treturn result, errNoContent\n\t}\n\n\tif failed > 0 {\n\t\treturn result, fmt.Errorf(\"%w: failed to fetch %d channels\", errPartialContent, failed)\n\t}\n\n\treturn result, nil\n}\n","sourceCodeStart":216,"sourceCodeEnd":239,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-twitch-channels.go#L216-L239","documentation":"Wraps errPartialContent after the twitch-channels widget fetched a list of channels and at least one (but not all) individual channel request failed. The widget still returns the channels that succeeded; the error signals degraded completeness to the partial-content rendering path.","triggerScenarios":"One or more channel logins in the channels list fail (rate limit, deleted channel, GQL error) while others succeed, and failed < len(channelLogins). If every channel fails, errNoContent is returned instead.","commonSituations":"A deleted/renamed Twitch channel left in the config; intermittent 429s from gql.twitch.tv when tracking many channels with a short cache time.","solutions":["Check the server logs for the matching 'Failed to fetch Twitch channel' lines to see which login failed and why","Remove or fix misspelled/deleted channel logins in the twitch-channels widget config","Increase cache-time or reduce the number of channels to avoid rate limiting"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Before configuring, sanity-check each login is a non-empty lowercase string\nfunc validTwitchLogin(l string) bool {\n\treturn l != \"\" && l == strings.ToLower(l) && !strings.ContainsAny(l, \" /\\u0000\")\n}","typeGuard":"func isPartialContent(err error) bool { return errors.Is(err, errPartialContent) }","tryCatchPattern":"channels, err := widget.getChannels()\nif errors.Is(err, errPartialContent) {\n    // render the successful channels; log the failed count\n    slog.Warn(\"twitch partial fetch\", \"err\", err)\n} else if err != nil {\n    return err\n}","preventionTips":["Prune deleted/renamed channels from the config when log lines flag them","Keep the channel list modest and cache long enough to avoid 429 partial failures","Distinguish errPartialContent from errNoContent with errors.Is before deciding to fail"],"tags":["twitch","partial-content","widget","rate-limit"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}