glanceapp/glance · error

body must be a string when body-type is 'string'

Error message

body must be a string when body-type is 'string'

What it means

The Custom API widget's .JSON option helper marshals the option value with encoding/json and panics with 'marshaling %s: %v' if json.Marshal fails. The template engine recovers the panic into a render error. Standard YAML-sourced values (strings, numbers, bools, maps, lists) always marshal; failures come from values JSON cannot represent.

Source

Thrown at internal/glance/widget-custom-api.go:163

			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)
		}

	} else if req.Method == "" {
		req.Method = http.MethodGet
	}

	httpReq, err := http.NewRequest(strings.ToUpper(req.Method), req.URL, req.bodyReader)
	if err != nil {
		return err
	}

	if len(req.Parameters) > 0 {
		httpReq.URL.RawQuery = req.Parameters.toQueryString()
	}

View on GitHub (pinned to 91324e8de7)

Solutions

  1. Replace .nan/.inf option values with real numbers, strings, or null and handle absence in the template
  2. If a number may be unknown, store it as a string or omit the key and use .FloatOr default
  3. Sanitize computed values with {{ if ... }} guards before passing to .JSON

Example fix

// before (glance.yml)
options:
  ratio: .nan
# template: {{ .JSON "ratio" }}
// after
options:
  ratio: 0.0
# or omit the key and use a default in the template
Defensive patterns

Strategy: validation

Validate before calling

if math.IsNaN(f) || math.IsInf(f, 0) {
    return errors.New("value not representable in JSON")
}
b, err := json.Marshal(f)

Type guard

func jsonMarshalable(v any) bool {
	_, err := json.Marshal(v)
	return err == nil
}

Try / catch

Wrap the .JSON call site in template logic that only runs for known-safe values; in Go code, pre-check non-finite floats with math.IsNaN/IsInf before marshaling, since encoding/json has no option to tolerate them.

Prevention

When it happens

Trigger: An option value that encoding/json rejects — most notably float NaN/Infinity (YAML .nan or .inf) — is passed to .JSON. marshal fails with 'json: unsupported value: NaN' and the panic fires.

Common situations: YAML config using .nan/.inf placeholders for 'unknown' numbers that then get embedded into a JSON request body via .JSON; values computed in a template pipeline that produce non-finite floats; options populated from upstream data containing non-finite numbers.

Related errors


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