glanceapp/glance · error
missing API token
Error message
missing API token
What it means
Inside Custom API templates you can build requests with template funcs (withQueryParameter, withStringBody, etc.) and execute them synchronously with getResponse. getResponse first calls req.initialize(), which parses and validates the (possibly template-substituted) URL, method and body; on failure it panics with 'initializing request: %v' and the render aborts with that message.
Source
Thrown at internal/glance/widget-dns-stats.go:316
func (p *pihole5TopBlockedDomains) UnmarshalJSON(data []byte) error {
// NOTE: do not change to piholeTopBlockedDomains type here or it will cause a stack overflow
// because of the UnmarshalJSON method getting called recursively
temp := make(map[string]int)
err := json.Unmarshal(data, &temp)
if err != nil {
*p = make(pihole5TopBlockedDomains)
} else {
*p = temp
}
return nil
}
func fetchPihole5Stats(instanceURL string, allowInsecure bool, token string, noGraph bool) (*dnsStats, error) {
if token == "" {
return nil, errors.New("missing API token")
}
requestURL := strings.TrimRight(instanceURL, "/") +
"/admin/api.php?summaryRaw&topItems&overTimeData10mins&auth=" + token
request, err := http.NewRequest("GET", requestURL, nil)
if err != nil {
return nil, err
}
var client = ternary(allowInsecure, defaultInsecureHTTPClient, defaultHTTPClient)
responseJson, err := decodeJsonFromRequest[pihole5StatsResponse](client, request)
if err != nil {
return nil, err
}
stats := &dnsStats{
TotalQueries: responseJson.TotalQueries,View on GitHub (pinned to 91324e8de7)
Solutions
- Inspect the rendered request: log the URL/method/body in the template ({{ .Log }} or render them into the output) to see what actually got substituted
- Ensure any option used in the request URL is defined in options: and non-empty before calling getResponse
- Build URLs with proper helpers instead of raw concatenation, so schemes/escaping stay valid
- Guard in the template: {{ if .options-derived-value }}{{ getResponse ... }}{{ end }}
Example fix
// before
{{ $r := (getResponses (withURL .StringOr "baseurl" "")).Response }}
// after: only issue the request when the base URL exists
{{ $base := .StringOr "baseurl" "" }}
{{ if $base }}{{ $r := (getResponse (withURL $base)).Response }}{{ end }} Defensive patterns
Strategy: validation
Validate before calling
// template-side: only call getResponse with a validated URL
{{ $u := .StringOr "baseurl" "" }}
{{ if and $u (strings.HasPrefix $u "http") }}
{{ getResponse (withURL $u) }}
{{ end }} Try / catch
Since the panic happens inside template execution, catch it at the Execute call: the template engine returns it as an error ('initializing request: ...'); isolate the failing widget render and show the message in the widget frame. Prevention
- Always default-check option-derived URLs with .StringOr and an {{ if }} guard before getResponse
- Build requests via the with* helpers rather than string concatenation so URLs stay well-formed
- Log the substituted URL/method when debugging — the panic message includes the underlying url.Error
When it happens
Trigger: A dynamically-built request ends up invalid after template substitution: an option-derived URL that is empty or malformed (http.Get on a template placeholder that resolved to nothing), an invalid HTTP method, or an unusable body content type. Example: {{ (getResponse (.URL "))).Response.Status }} with no url option.
Common situations: Templating the URL/host from options where the option is missing or resolves to an empty string; constructing URLs by string concatenation that yields a scheme-less result; passing a computed method string with whitespace/newlines from YAML.
Related errors
- invalid body type, must be either 'json' or 'string'
- invalid response JSON
- body must be a string when body-type is 'string'
- %d %s
- usernames must be at least 3 characters
AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15).
Data as JSON: /api/errors/d5f25d8a10f578cc.
Report an issue: GitHub.