GoogleCloudPlatform/microservices-demo · error

failed to unmarshal body

Error message

failed to unmarshal body

What it means

json.Unmarshal failed to decode the assistant's response body into LLMResponse ({content, details}). The assistant replied, but the body is not valid JSON or does not match the expected schema (HTML error page, empty body, or version drift).

Solutions

  1. Check res.StatusCode before decoding; handle non-2xx responses (often non-JSON) separately.
  2. Log the raw body to inspect the actual payload shape.
  3. Align LLMResponse with the assistant's real schema or decode into a map first.
  4. Ensure the assistant always returns application/json, even on internal errors.
Defensive patterns

Strategy: type-guard

When it happens

Trigger: Thrown at src/frontend/handlers.go:489 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of GoogleCloudPlatform/microservices-demo@72ba613a05 (2026-09-02). Data as JSON: /api/errors/d9acdb54e45f1ec1. Report an issue: GitHub.

Appendix: source

Thrown at src/frontend/handlers.go:489

	req.Header.Set("Accept", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		renderHTTPError(log, r, w, errors.Wrap(err, "failed to send request"), http.StatusInternalServerError)
		return
	}

	body, err := io.ReadAll(res.Body)
	if err != nil {
		renderHTTPError(log, r, w, errors.Wrap(err, "failed to read response"), http.StatusInternalServerError)
		return
	}

	fmt.Printf("%+v\n", body)
	fmt.Printf("%+v\n", res)

	err = json.Unmarshal(body, &response)
	if err != nil {
		renderHTTPError(log, r, w, errors.Wrap(err, "failed to unmarshal body"), http.StatusInternalServerError)
		return
	}

	// respond with the same message
	json.NewEncoder(w).Encode(Response{Message: response.Content})

	w.WriteHeader(http.StatusOK)
}

func (fe *frontendServer) setCurrencyHandler(w http.ResponseWriter, r *http.Request) {
	log := r.Context().Value(ctxKeyLog{}).(logrus.FieldLogger)
	cur := r.FormValue("currency_code")
	payload := validator.SetCurrencyPayload{Currency: cur}
	if err := payload.Validate(); err != nil {
		renderHTTPError(log, r, w, validator.ValidationErrorResponse(err), http.StatusUnprocessableEntity)
		return
	}
	log.WithField("curr.new", payload.Currency).WithField("curr.old", currentCurrency(r)).

View on GitHub (pinned to 72ba613a05)