glanceapp/glance · error
could not fetch list of watch UUIDs: %v
Error message
could not fetch list of watch UUIDs: %v
What it means
Returned by fetchWatchUUIDsFromChangeDetection in internal/glance/widget-changedetection.go when the HTTP GET to {instanceURL}/api/v1/watch fails or its body cannot be decoded into a map[string]struct{} via decodeJsonFromRequest. This wraps transport errors, non-2xx responses, and JSON decode failures into a single message.
Source
Thrown at internal/glance/widget-changedetection.go:107
type changeDetectionResponseJson struct {
Title string `json:"title"`
URL string `json:"url"`
LastChanged int64 `json:"last_changed"`
DateCreated int64 `json:"date_created"`
PreviousHash string `json:"previous_md5"`
}
func fetchWatchUUIDsFromChangeDetection(instanceURL string, token string) ([]string, error) {
request, _ := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/watch", instanceURL), nil)
if token != "" {
request.Header.Add("x-api-key", token)
}
uuidsMap, err := decodeJsonFromRequest[map[string]struct{}](defaultHTTPClient, request)
if err != nil {
return nil, fmt.Errorf("could not fetch list of watch UUIDs: %v", err)
}
uuids := make([]string, 0, len(uuidsMap))
for uuid := range uuidsMap {
uuids = append(uuids, uuid)
}
return uuids, nil
}
func fetchWatchesFromChangeDetection(instanceURL string, requestedWatchIDs []string, token string) (changeDetectionWatchList, error) {
watches := make(changeDetectionWatchList, 0, len(requestedWatchIDs))
if len(requestedWatchIDs) == 0 {
return watches, nil
}
View on GitHub (pinned to 91324e8de7)
Solutions
- curl -H 'x-api-key: TOKEN' {instanceURL}/api/v1/watch and confirm a JSON object keyed by UUID comes back.
- Verify the token matches Settings > API in changedetection.io and that the widget key: is set (not empty).
- Check the instance URL scheme/host and that the host running glance can reach it (DNS, firewall, TLS).
- If a proxy sits in front, ensure it passes the x-api-key header and does not rewrite /api/v1/watch.
Defensive patterns
Strategy: retry
Validate before calling
// before building the widget, probe the API contract
req, _ := http.NewRequest("GET", instanceURL+"/api/v1/watch", nil)
if token != "" {
req.Header.Add("x-api-key", token)
}
resp, err := defaultHTTPClient.Do(req)
if err != nil || resp.StatusCode != 200 {
return fmt.Errorf("changedetection API unreachable or unauthorized: %v", err)
}
defer resp.Body.Close()
if ct := resp.Header.Get("Content-Type"); !strings.Contains(ct, "json") {
return errors.New("changedetection API did not return JSON (check URL/proxy)")
} Try / catch
uuids, err := fetchWatchUUIDsFromChangeDetection(url, token)
if err != nil {
// transient network or auth issue: skip this refresh, keep last good render
slog.Warn("changedetection fetch failed", "error", err)
return
} Prevention
- Store the API token in glance secrets/env, not inline, so it survives config edits.
- Point the widget at the instance root; the code appends /api/v1/watch itself.
- Monitor the instance with a simple uptime check so a dead instance is caught early.
When it happens
Trigger: GET {url}/api/v1/watch with optional x-api-key header returns 401/403 (bad token), connection refused/DNS failure (bad URL), a reverse-proxy HTML error page instead of JSON, or a changedetection.io version whose API payload is not a UUID-keyed object.
Common situations: Wrong or missing api token in the widget's token field; instance URL pointing at the UI path instead of the API root; self-hosted instance behind a proxy that intercepts /api; changedetection.io major version change altering the response shape.
Related errors
- fetching session ID: %v
- failed to retrieve any content
- %w: could not get %d watches
- %d %s
- checking session ID: %v
AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15).
Data as JSON: /api/errors/ed5fdde487c9b882.
Report an issue: GitHub.