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

  1. 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
  2. Ensure any option used in the request URL is defined in options: and non-empty before calling getResponse
  3. Build URLs with proper helpers instead of raw concatenation, so schemes/escaping stay valid
  4. 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

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


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