ory/hydra · error
Failed to encode request body: %s
Error message
Failed to encode request body: %s
What it means
This error is returned by the POSTdevice handler in the CLI device-flow helper when json.Marshal fails to serialize the {"user_code": ...} payload that is PUT to the Hydra admin device-accept endpoint. json.Marshal on a map[string]string practically never fails (no channels, funcs, or unsupported types), so hitting this indicates a programming error rather than a runtime condition. It is surfaced to the client as a plain-text 500 via http.Error.
Source
Thrown at cmd/cmd_perform_device_flow.go:201
if challenge == "" {
http.Error(w, "device_challenge is required", http.StatusBadRequest)
return
}
// Accept the user code with a hand-rolled request instead of the generated
// client: other modules in this repository compile this package against the
// released hydra-client-go/v2 module, which predates the device
// authorization API.
cfg := s.cl.GetConfig()
if len(cfg.Servers) == 0 {
http.Error(w, "No Hydra endpoint is configured", http.StatusInternalServerError)
return
}
acceptURL := strings.TrimSuffix(cfg.Servers[0].URL, "/") +
"/admin/oauth2/auth/requests/device/accept?device_challenge=" + url.QueryEscape(challenge)
body, err := json.Marshal(map[string]string{"user_code": userCode})
if err != nil {
http.Error(w, fmt.Sprintf("Failed to encode request body: %s", err), http.StatusInternalServerError)
return
}
req, err := http.NewRequestWithContext(r.Context(), http.MethodPut, acceptURL, bytes.NewReader(body))
if err != nil {
http.Error(w, fmt.Sprintf("Failed to create request: %s", err), http.StatusInternalServerError)
return
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
hc := cfg.HTTPClient
if hc == nil {
hc = http.DefaultClient
}
res, err := hc.Do(req)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to accept user code request: %s", err), http.StatusInternalServerError)
returnView on GitHub (pinned to 4174065ffb)
Solutions
- Verify the marshaled value is only plain strings; if it must hold other types, use a typed struct with JSON tags instead of map[string]string.
- Log the underlying marshal error (it already appears in the 500 body) and inspect the value being marshaled.
- Keep the http.Error fallback so failures return 500 rather than panicking; no client-side fix is possible.
Example fix
// before
body, err := json.Marshal(map[string]string{"user_code": userCode})
// after
type acceptReq struct {
UserCode string `json:"user_code"`
}
body, err := json.Marshal(acceptReq{UserCode: userCode}) Defensive patterns
Strategy: validation
Validate before calling
payload := map[string]string{"user_code": userCode}
if _, err := json.Marshal(payload); err != nil {
return fmt.Errorf("payload unserializable: %w", err)
} Type guard
func marshalable(v any) bool {
_, err := json.Marshal(v)
return err == nil
} Try / catch
body, err := json.Marshal(payload)
if err != nil {
log.Printf("marshal failed: %v", err)
http.Error(w, "internal error", http.StatusInternalServerError)
return
} Prevention
- Keep request payloads as plain string maps or tagged structs — never channels, funcs, or cyclic refs
- Write a unit test that marshals every request payload type
- Prefer structs with json tags over map[string]string for evolving payloads
When it happens
Trigger: json.Marshal(map[string]string{"user_code": userCode}) returns an error at cmd/cmd_perform_device_flow.go:201. With the current literal map of strings this cannot happen at runtime; it would only fail if the payload type were changed to include unsupported values (channels, funcs, cyclic structures) or a custom MarshalJSON returning an error.
Common situations: Practically never seen in production with this exact code. Developers refactoring the handler to send structured payloads (e.g. embedding a struct with unmarshalable fields, or passing context through the map) can introduce it. Custom user_code wrapper types with faulty MarshalJSON methods are the realistic path.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- err.Error()
- cookiex: payload must be a flat JSON object with string valu
- errKeyNotFound
- http(s) loader disabled
- can not serve request over insecure http
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/6564118bd88d0ef5.
Report an issue: GitHub.