cloudflare/cloudflared · error
failed to serialize json body
Error message
failed to serialize json body
What it means
RESTClient.sendRequest marshals the request body to JSON before sending it to the Cloudflare API and wraps json.Marshal failures with this message. It means the Go struct passed as the request body could not be serialized, which for well-formed API request types is nearly impossible — it usually indicates a type that JSON cannot represent (channels, funcs, cycles) or a custom MarshalJSON returning an error.
Source
Thrown at cfapi/base_client.go:91
zoneLevel: *zoneLevelEndpoint,
accountRoutes: *accountRoutesEndpoint,
accountVnets: *accountVnetsEndpoint,
},
authToken: authToken,
userAgent: userAgent,
client: http.Client{
Transport: &httpTransport,
Timeout: defaultTimeout,
},
log: log,
}, nil
}
func (r *RESTClient) sendRequest(method string, url url.URL, body interface{}) (*http.Response, error) {
var bodyReader io.Reader
if body != nil {
if bodyBytes, err := json.Marshal(body); err != nil {
return nil, errors.Wrap(err, "failed to serialize json body")
} else {
bodyReader = bytes.NewBuffer(bodyBytes)
}
}
req, err := http.NewRequest(method, url.String(), bodyReader)
if err != nil {
return nil, errors.Wrapf(err, "can't create %s request", method)
}
req.Header.Set("User-Agent", r.userAgent)
if bodyReader != nil {
req.Header.Set("Content-Type", jsonContentType)
}
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.authToken))
req.Header.Add("Accept", "application/json;version=1")
return r.client.Do(req)
}
View on GitHub (pinned to 2253eeeb25)
Solutions
- Inspect the body type passed to the API call; remove unsupported fields (chan, func, circular references).
- Test json.Marshal(body) directly to see the underlying error.
- Use the library's defined request structs (e.g. cfapi.Route, CreateTunnelParams-derived types) rather than ad-hoc maps.
- Fix any custom MarshalJSON implementations that return errors.
Example fix
// before
client.CreateTunnel(t, &Tunnel{Conn: make(chan int)})
// after
client.CreateTunnel(t, &cfapi.Tunnel{Name: name, Secret: secret}) Defensive patterns
Strategy: validation
Validate before calling
if _, err := json.Marshal(body); err != nil {
return fmt.Errorf("request body not serializable: %w", err)
} Try / catch
if err := client.CreateTunnel(t, params); err != nil {
if strings.Contains(err.Error(), "failed to serialize json body") {
return fmt.Errorf("bad request body type %T: %w", params, err)
}
return err
} Prevention
- Use the library's request struct types instead of ad-hoc maps/interfaces.
- Never put chan, func, or cyclic pointers in request bodies.
- Test json.Marshal on custom body types in unit tests.
When it happens
Trigger: Passing a body containing unsupported types (chan, func, cyclic pointers) or a type whose custom MarshalJSON errors when calling CreateTunnel, AddRoute, DeleteRoute, GetByIP, etc.
Common situations: Constructing route/tunnel request structs with unusual field types or embedding non-serializable values; typos leading to interface{} values holding unserializable data.
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
- failed to decode response
- the Cloudflare API response was an unexpected type
- error parsing OriginCert: %v
- originCert marshal failed: %v
- failed to create account level endpoint
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/bdfdf093a6ca6e84.
Report an issue: GitHub.