glanceapp/glance · error
invalid response JSON
Error message
invalid response JSON
What it means
Custom API widget templates call .Subrequest "key" to get data pre-fetched by a subrequests entry. If the key is not defined in the widget's subrequests map, there is no safe zero value to return, so the code panics with 'subrequest with key %q has not been defined'; the template engine converts the panic into an execution error for that render.
Source
Thrown at internal/glance/widget-custom-api.go:265
}
defer resp.Body.Close()
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) {View on GitHub (pinned to 91324e8de7)
Solutions
- Add a subrequests entry with the exact key the template passes to .Subrequest
- Fix typos/case mismatches between template argument and subrequests key
- Keep shared partials self-consistent: any widget including the partial must define every subrequest it uses
Example fix
// before (glance.yml)
- type: custom-api
template: |
{{ (.Subrequest "stats").JSON.Get "uptime" }}
// after: define the referenced subrequest
- type: custom-api
template: |
{{ (.Subrequest "stats").JSON.Get "uptime" }}
subrequests:
stats:
url: http://host/api/stats Defensive patterns
Strategy: validation
Validate before calling
// before rendering, verify every key the template uses exists
for _, key := range templateSubrequestKeys {
if _, ok := subrequests[key]; !ok {
return fmt.Errorf("subrequest %q missing from config", key)
}
} Try / catch
Rely on template recovery: html/template turns the panic into an execution error containing 'subrequest with key %q has not been defined'; log that error per-widget so one bad widget does not take down the page.
Prevention
- Define every subrequest a template (or its partials) references in the same widget block
- Keep a naming convention (e.g. lowercase snake keys) to avoid case-mismatch panics
- When sharing partials across widgets, document the required subrequest keys
When it happens
Trigger: Template references .Subrequest "stats" but the widget config has no subrequests: stats: entry (typo, renamed key, or the subrequest was removed while the template still references it). Also occurs when a shared partial expects a subrequest the including widget never declared.
Common situations: Reusing a template across several Custom API widgets where only some define the subrequest; renaming a subrequest key in glance.yml without updating the template; case-sensitivity mismatches.
Related errors
- invalid body type, must be either 'json' or 'string'
- missing API token
- body must be a string when body-type is 'string'
- usernames must be at least 3 characters
- invalid first day of week
AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15).
Data as JSON: /api/errors/c647c32b8e2ac19a.
Report an issue: GitHub.