{"record":{"id":"63aebdd0bddcacfc","repo":"gastownhall/beads","slug":"marshal-request-body-w","errorCode":null,"errorMessage":"marshal request body: %w","messagePattern":"marshal request body: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/notion/client.go","lineNumber":260,"sourceCode":"}\n\nfunc (c *Client) doRequest(ctx context.Context, method, path string, requestBody interface{}) ([]byte, error) {\n\tif c == nil {\n\t\treturn nil, fmt.Errorf(\"notion client is nil\")\n\t}\n\tif strings.TrimSpace(c.Token) == \"\" {\n\t\treturn nil, fmt.Errorf(\"Notion token not configured\")\n\t}\n\thttpClient := c.HTTPClient\n\tif httpClient == nil {\n\t\thttpClient = &http.Client{Timeout: DefaultTimeout}\n\t}\n\n\tvar bodyReader io.Reader\n\tif requestBody != nil {\n\t\tpayload, err := json.Marshal(requestBody)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"marshal request body: %w\", err)\n\t\t}\n\t\tbodyReader = bytes.NewReader(payload)\n\t}\n\n\trequestURL := path\n\tif !strings.HasPrefix(requestURL, \"http://\") && !strings.HasPrefix(requestURL, \"https://\") {\n\t\trequestURL = strings.TrimSuffix(c.BaseURL, \"/\") + path\n\t}\n\treq, err := http.NewRequestWithContext(ctx, method, requestURL, bodyReader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+c.Token)\n\treq.Header.Set(\"Notion-Version\", c.NotionVersion)\n\treq.Header.Set(\"Accept\", \"application/json\")\n\tif requestBody != nil {\n\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\t}","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/notion/client.go#L242-L278","documentation":"doRequest could not JSON-serialize the request payload passed as requestBody. The error wraps the json.Marshal error, so the underlying cause (unsupported type, channel/func field, invalid value) is in the chain. It fires only when requestBody != nil.","triggerScenarios":"Passing a requestBody containing values json cannot encode: a struct field of type chan, func, or complex; an unexported-fields-only struct (marshals but often fine) or types with custom MarshalJSON that return errors; passing a map with non-string keys of an unsupported kind.","commonSituations":"Users build the request struct with a field typed as interface{} holding a channel or func; copy-pasted types with json:\"-\"-style custom marshaling gone wrong; passing *time.Time wrappers with bad MarshalJSON implementations.","solutions":["Inspect the wrapped error (%w chain) to identify the offending field/type reported by encoding/json.","Ensure requestBody is a plain JSON-serializable struct/map with exported fields and proper json tags.","Marshal it yourself first in a test: b, err := json.Marshal(req); check err to reproduce locally.","Set the field to omitempty or remove unsupported fields from the request type."],"exampleFix":"// before\ntype req struct {\n    Callback func() `json:\"callback\"`\n}\nclient.Query(ctx, req{Callback: fn}) // marshal error\n\n// after\ntype req struct {\n    Name string `json:\"name\"`\n}\nclient.Query(ctx, req{Name: \"x\"})","handlingStrategy":"validation","validationCode":"if requestBody != nil {\n    if _, err := json.Marshal(requestBody); err != nil {\n        return fmt.Errorf(\"invalid request body: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"marshal request body\") {\n    log.Printf(\"request body not JSON-serializable: %v\", err)\n}","preventionTips":["Use typed request structs with exported fields and json tags instead of ad-hoc maps/interface{}.","Keep channels, funcs, and complex numbers out of request types.","Add unit tests that json.Marshal every request payload your code builds."],"tags":["notion","json","serialization","request-body"],"backgroundTag":"json-marshal-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}