glanceapp/glance · error
invalid body type, must be either 'json' or 'string'
Error message
invalid body type, must be either 'json' or 'string'
What it means
In the Custom API widget, the .JSON "key" template function marshals a configured option to a JSON string. Unlike FloatOr/StringOr/BoolOr it has no default fallback: if the key is absent from the widget's options map it panics with 'key %q does not exist in options'. Go's template engine recovers the panic and reports it as a template execution error, so the widget render fails with that message.
Source
Thrown at internal/glance/widget-custom-api.go:149
return defaultValue
}
func (req *CustomAPIRequest) initialize() error {
if req == nil || req.URL == "" {
return nil
}
if req.Body != nil {
if req.Method == "" {
req.Method = http.MethodPost
}
if req.BodyType == "" {
req.BodyType = "json"
}
if req.BodyType != "json" && req.BodyType != "string" {
return errors.New("invalid body type, must be either 'json' or 'string'")
}
switch req.BodyType {
case "json":
encoded, err := json.Marshal(req.Body)
if err != nil {
return fmt.Errorf("marshaling body: %v", err)
}
req.bodyReader = bytes.NewReader(encoded)
case "string":
bodyAsString, ok := req.Body.(string)
if !ok {
return errors.New("body must be a string when body-type is 'string'")
}
req.bodyReader = strings.NewReader(bodyAsString)
}View on GitHub (pinned to 91324e8de7)
Solutions
- Open the Custom API widget's config and add the missing key under options: with any YAML value
- Check for typos/case differences between the template's .JSON argument and the options key
- If the option is genuinely optional, use .StringOr/.FloatOr/.BoolOr with defaults, or guard in the template
- Reload Glance config and re-render the widget to confirm the error clears
Example fix
// before (glance.yml)
- type: custom-api
template: |
{{ .JSON "webhook" }}
options:
url: http://x
// after: add the referenced key
- type: custom-api
template: |
{{ .JSON "webhook" }}
options:
url: http://x
webhook: "https://hooks.example/abc" Defensive patterns
Strategy: validation
Validate before calling
// template-side guard before calling .JSON
{{ if .Options.HasKey "webhook" }}{{ .JSON "webhook" }}{{ end }} Try / catch
Go's html/template recovers panics during Execute: capture the returned error and surface its message (which contains 'key %q does not exist in options') to the config author instead of crashing the server. Outside templates, check the map with `value, ok := options[key]; if !ok { ... }` before use. Prevention
- Keep templates and options in the same glance.yml file so key references stay in sync
- For optional data prefer .StringOr/.FloatOr/.BoolOr which default instead of panicking
- Lint custom templates by rendering them once with a full options fixture before deploy
When it happens
Trigger: A template under template or template-partial calls .JSON "foo" but the widget config has no option foo: (renamed key, typo, or the option lives on a different widget instance).
Common situations: Refactoring: the template is updated to reference a new option key but glance.yml is not; copy-pasting a template partial that expects options the target widget does not define; case mismatches (Option vs option).
Related errors
- invalid response JSON
- missing API token
- body must be a string when body-type is 'string'
- invalid first day of week
- initializing primary request: %v
AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15).
Data as JSON: /api/errors/a56c03ca9b878573.
Report an issue: GitHub.