{"record":{"id":"bdfdf093a6ca6e84","repo":"cloudflare/cloudflared","slug":"failed-to-serialize-json-body","errorCode":null,"errorMessage":"failed to serialize json body","messagePattern":"failed to serialize json body","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cfapi/base_client.go","lineNumber":91,"sourceCode":"\t\t\tzoneLevel:     *zoneLevelEndpoint,\n\t\t\taccountRoutes: *accountRoutesEndpoint,\n\t\t\taccountVnets:  *accountVnetsEndpoint,\n\t\t},\n\t\tauthToken: authToken,\n\t\tuserAgent: userAgent,\n\t\tclient: http.Client{\n\t\t\tTransport: &httpTransport,\n\t\t\tTimeout:   defaultTimeout,\n\t\t},\n\t\tlog: log,\n\t}, nil\n}\n\nfunc (r *RESTClient) sendRequest(method string, url url.URL, body interface{}) (*http.Response, error) {\n\tvar bodyReader io.Reader\n\tif body != nil {\n\t\tif bodyBytes, err := json.Marshal(body); err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"failed to serialize json body\")\n\t\t} else {\n\t\t\tbodyReader = bytes.NewBuffer(bodyBytes)\n\t\t}\n\t}\n\n\treq, err := http.NewRequest(method, url.String(), bodyReader)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"can't create %s request\", method)\n\t}\n\treq.Header.Set(\"User-Agent\", r.userAgent)\n\tif bodyReader != nil {\n\t\treq.Header.Set(\"Content-Type\", jsonContentType)\n\t}\n\treq.Header.Add(\"Authorization\", fmt.Sprintf(\"Bearer %s\", r.authToken))\n\treq.Header.Add(\"Accept\", \"application/json;version=1\")\n\treturn r.client.Do(req)\n}\n","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/cfapi/base_client.go#L73-L109","documentation":"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.","triggerScenarios":"Passing a body containing unsupported types (chan, func, cyclic pointers) or a type whose custom MarshalJSON errors when calling CreateTunnel, AddRoute, DeleteRoute, GetByIP, etc.","commonSituations":"Constructing route/tunnel request structs with unusual field types or embedding non-serializable values; typos leading to interface{} values holding unserializable data.","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."],"exampleFix":"// before\nclient.CreateTunnel(t, &Tunnel{Conn: make(chan int)})\n// after\nclient.CreateTunnel(t, &cfapi.Tunnel{Name: name, Secret: secret})","handlingStrategy":"validation","validationCode":"if _, err := json.Marshal(body); err != nil {\n\treturn fmt.Errorf(\"request body not serializable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := client.CreateTunnel(t, params); err != nil {\n\tif strings.Contains(err.Error(), \"failed to serialize json body\") {\n\t\treturn fmt.Errorf(\"bad request body type %T: %w\", params, err)\n\t}\n\treturn err\n}","preventionTips":["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."],"tags":["go","json","serialization","api-client"],"backgroundTag":"json-marshal-failed","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}