glanceapp/glance · error

unexpected status code %d from %s

Error message

unexpected status code %d from %s

What it means

Returned by rssWidget.fetchItemsFromFeedTask (internal/glance/widget-rss.go:227) when a feed URL responds with a status other than 200 (or 304 when a cached copy exists). The request already carries a Glance user-agent; non-200 means the server refused or failed the fetch: 403 anti-bot, 404 moved feed, 410 gone, 429 rate-limited, or 5xx outage.

Source

Thrown at internal/glance/widget-rss.go:227

	}
	widget.cachedFeedsMutex.Unlock()

	for key, value := range request.Headers {
		req.Header.Set(key, value)
	}

	resp, err := defaultHTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNotModified && isCached {
		return cache.items, nil
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("unexpected status code %d from %s", resp.StatusCode, request.URL)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	feed, err := feedParser.ParseString(string(body))
	if err != nil {
		return nil, err
	}

	if request.Limit > 0 && len(feed.Items) > request.Limit {
		feed.Items = feed.Items[:request.Limit]
	}

	items := make(rssFeedItemList, 0, len(feed.Items))

View on GitHub (pinned to 91324e8de7)

Solutions

  1. Confirm the URL with curl -A 'Glance' and follow redirects to find the current feed address
  2. If the site blocks bots, use its RSS-specific domain or a feed proxy/burner URL that permits fetchers
  3. Increase the page cache-time so the feed is fetched less often (fixes 429)
  4. Remove feeds that are permanently gone (410)
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check a feed URL's health before adding it to the widget
resp, err := http.Get(feedURL)
if err != nil || (resp.StatusCode != 200 && resp.StatusCode != 304) {
    // do not add / fix the URL
}

Try / catch

if err != nil && strings.Contains(err.Error(), "unexpected status code") {
    // 403 => bot blocking; 404/410 => moved/gone; 429 => back off; 5xx => retry later
}

Prevention

When it happens

Trigger: GET {feed-url} returns 403 (Cloudflare/WAF blocking the Glance UA), 404/410 (feed path moved), 429 (refreshing too often), 301→non-200 chain where the redirect target errors, or 5xx from the origin. 304 is tolerated only when isCached is true; a 304 without cache still errors.

Common situations: Popular blogs behind Cloudflare blocking non-browser agents; feeds moved to /rss or /feed without redirect; widget refresh interval set aggressively low triggering 429s; origin outages.

Related errors


AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15). Data as JSON: /api/errors/9529468de01c19d5. Report an issue: GitHub.