{"record":{"id":"26152cced5882e2d","repo":"glanceapp/glance","slug":"could-not-solve-reddit-challenge","errorCode":null,"errorMessage":"could not solve reddit challenge","messagePattern":"could not solve reddit challenge","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/widget-reddit.go","lineNumber":225,"sourceCode":"\t\trequestURL = fmt.Sprintf(\"%s/r/%s/%s.json?%s\", baseURL, widget.Subreddit, widget.SortBy, query.Encode())\n\t}\n\n\tif widget.RequestURLTemplate != \"\" {\n\t\trequestURL = strings.ReplaceAll(widget.RequestURLTemplate, \"{REQUEST-URL}\", requestURL)\n\t} else if widget.Proxy.client != nil {\n\t\tclient = widget.Proxy.client\n\t}\n\n\trequest, err := http.NewRequest(\"GET\", requestURL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\trequest.Header = headers\n\n\tloid, err := getRedditLoidCookie()\n\tif err != nil {\n\t\tfmt.Printf(\"Error fetching reddit loid cookie: %v\\n\", err)\n\t\treturn nil, errors.New(\"could not solve reddit challenge\")\n\t}\n\trequest.AddCookie(&http.Cookie{Name: \"loid\", Value: loid})\n\n\tresponseJson, err := decodeJsonFromRequest[subredditResponseJson](client, request)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(responseJson.Data.Children) == 0 {\n\t\treturn nil, fmt.Errorf(\"no posts found\")\n\t}\n\n\tposts := make(forumPostList, 0, len(responseJson.Data.Children))\n\n\tfor i := range responseJson.Data.Children {\n\t\tpost := &responseJson.Data.Children[i].Data\n\n\t\tif post.Stickied || post.Pinned {","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-reddit.go#L207-L243","documentation":"Returned at update time by the reddit widget when fetching the anonymous 'loid' cookie (Reddit's device-ID challenge cookie) fails. Before requesting subreddit JSON, Glance calls getRedditLoidCookie; any error there is swallowed into a log line and replaced with this generic message, so the underlying cause (network, DNS, proxy, or Reddit blocking) is hidden.","triggerScenarios":"Reddit's loid endpoint being unreachable from the Glance host; DNS failure for reddit.com; an egress proxy/firewall blocking the cookie request; Reddit rate-limiting or geo-blocking the server's IP; the anonymous challenge flow changing on Reddit's side.","commonSituations":"Self-hosted servers in datacenter IP ranges that Reddit challenges or blocks; Docker containers with broken DNS; corporate proxies stripping cookies; Reddit outages or API changes after a site redesign.","solutions":["From the Glance host, verify plain reachability of reddit.com (curl -I https://www.reddit.com) and fix DNS/proxy/firewall if it fails","Set the widget's proxy field (or global proxy env vars) so the Reddit traffic egresses from a non-blocked IP","Configure app-auth (name/id/secret) to use authenticated OAuth access instead of the anonymous loid flow","If Reddit is rate-limiting, increase cache duration or reduce the number of reddit widgets to lower request frequency"],"exampleFix":"# before\n- type: reddit\n  subreddit: selfhosted\n\n# after (authenticated app access bypasses the loid challenge)\n- type: reddit\n  subreddit: selfhosted\n  app-auth:\n    name: my-glance-app\n    id: abc123\n    secret: xyz789","handlingStrategy":"retry","validationCode":"import urllib.request\ntry:\n    urllib.request.urlopen('https://www.reddit.com', timeout=10)\n    print('reddit reachable')\nexcept Exception as e:\n    print('reddit NOT reachable from this host:', e)","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"could not solve reddit challenge\") {\n    // transient: widget already shows an error state and the next update cycle retries;\n    // if persistent, check egress, set proxy, or switch to app-auth instead of retry-looping\n    slog.Warn(\"reddit challenge failed; will retry next update\", \"error\", err)\n}","preventionTips":["Verify egress to reddit.com from the Glance host before deploying reddit widgets","Route traffic through the widget's proxy option when the server IP is blocked","Prefer app-auth OAuth credentials for reliable, higher-limit access","Keep few reddit widgets and rely on the built-in 30-minute cache to avoid rate limits"],"tags":["runtime","network","reddit","proxy","rate-limit"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}