glanceapp/glance · error

%d %s

Error message

%d %s

What it means

Returned by the custom API response handler when the HTTP status is outside 200-299 and the body is not valid JSON: fmt.Errorf("%d %s", resp.StatusCode, http.StatusText(resp.StatusCode)) yields messages like "502 Bad Gateway" or "401 Unauthorized". On 2xx statuses invalid JSON produces a different error ("invalid response JSON"), so this format specifically means non-2xx + non-JSON body.

Source

Thrown at internal/glance/widget-custom-api.go:268

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

	body := strings.TrimSpace(string(bodyBytes))

	if !req.SkipJSONValidation && body != "" && !gjson.Valid(body) {
		if 200 <= resp.StatusCode && resp.StatusCode < 300 {
			truncatedBody, isTruncated := limitStringLength(body, 100)
			if isTruncated {
				truncatedBody += "... <truncated>"
			}

			slog.Error("Invalid response JSON in custom API widget", "url", req.httpRequest.URL.String(), "body", truncatedBody)
			return nil, errors.New("invalid response JSON")
		}

		return nil, fmt.Errorf("%d %s", resp.StatusCode, http.StatusText(resp.StatusCode))

	}

	return &customAPIResponseData{
		JSON:     decoratedGJSONResult{gjson.Parse(body)},
		Response: resp,
	}, nil
}

func fetchAndRenderCustomAPIRequest(
	primaryReq *CustomAPIRequest,
	subReqs map[string]*CustomAPIRequest,
	options customAPIOptions,
	tmpl *template.Template,
) (template.HTML, error) {
	var primaryData *customAPIResponseData
	subData := make(map[string]*customAPIResponseData, len(subReqs))
	var err error

View on GitHub (pinned to 91324e8de7)

Solutions

  1. curl the exact URL with the same headers from the widget config and inspect the status code and body.
  2. Fix auth: add/refresh the API key or token header the endpoint expects.
  3. Correct the URL/path (404) or scheme/host (502).
  4. If the endpoint legitimately returns non-JSON error bodies on failure, consider options that tolerate it (e.g. skip JSON validation) or accept the widget showing the error status.
Defensive patterns

Strategy: try-catch

Try / catch

data, err := executeCustomAPIRequest(req)
if err != nil {
    if strings.Contains(err.Error(), "invalid response JSON") {
        // 2xx but bad JSON: log body sample, likely API contract change
    } else {
        // "NNN Status Text": HTTP-level failure — auth, proxy, or wrong URL
    }
    return nil, err
}

Prevention

When it happens

Trigger: Any custom-api request (primary or subrequest) whose endpoint returns e.g. 502/503 from a reverse proxy HTML error page, 401/403 from an auth wall returning HTML, or 404 for a wrong URL path.

Common situations: Expired API key so the gateway returns an HTML login page; wrong URL or path segment; upstream service down and the proxy's error page is HTML; Cloudflare challenge pages.

Related errors


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