{"record":{"id":"30ca6ec06b52b896","repo":"gastownhall/beads","slug":"failed-to-marshal-request-w","errorCode":null,"errorMessage":"failed to marshal request: %w","messagePattern":"failed to marshal request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/linear/client.go","lineNumber":354,"sourceCode":"\tif statusCode == http.StatusUnauthorized && c.AuthMode == AuthModeOAuth {\n\t\tdebug.Logf(\"oauth: received 401, invalidating token and retrying\")\n\t\tc.TokenManager.Invalidate()\n\t\tdata, _, retryErr := c.executeOnce(ctx, req)\n\t\tif retryErr != nil {\n\t\t\treturn nil, retryErr\n\t\t}\n\t\treturn data, nil\n\t}\n\n\treturn nil, err\n}\n\n// executeOnce performs the actual HTTP request loop with rate-limit retries.\n// Returns the response data, the last HTTP status code encountered, and any error.\nfunc (c *Client) executeOnce(ctx context.Context, req *GraphQLRequest) (json.RawMessage, int, error) {\n\tbody, err := json.Marshal(req)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"failed to marshal request: %w\", err)\n\t}\n\n\tvar lastErr error\n\tvar lastStatus int\n\tfor attempt := 0; attempt <= MaxRetries; attempt++ {\n\t\tif rlErr := c.circuitBreakerError(); rlErr != nil {\n\t\t\treturn nil, lastStatus, rlErr\n\t\t}\n\n\t\thttpReq, err := http.NewRequestWithContext(ctx, \"POST\", c.Endpoint, bytes.NewReader(body))\n\t\tif err != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"failed to create request: %w\", err)\n\t\t}\n\n\t\thttpReq.Header.Set(\"Content-Type\", \"application/json\")\n\t\tauthValue, err := c.authHeader()\n\t\tif err != nil {\n\t\t\treturn nil, 0, err","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/linear/client.go#L336-L372","documentation":"executeOnce serializes the GraphQLRequest to JSON before sending it. If json.Marshal fails — which for well-formed structs is rare but possible with unsupported values (e.g. channels, funcs, or NaN-like numbers injected via custom types) — the client returns 'failed to marshal request' wrapped around the marshal error before any HTTP call is made.","triggerScenarios":"Calling Execute with a GraphQLRequest whose Variables (or other fields) contain values json.Marshal cannot encode: json.RawMessage holding invalid JSON, cyclic data structures, unsupported types (chan, func, complex), or NaN/Inf float values.","commonSituations":"Passing variables built from dynamic data with cycles; injecting json.RawMessage from another marshal step that produced invalid bytes; custom types with a broken MarshalJSON implementation returning an error.","solutions":["Inspect the wrapped error to identify the offending field/type in the request variables","Fix or remove the value that cannot be marshaled (cycle, unsupported type, invalid RawMessage)","Validate custom MarshalJSON implementations on variable types","Marshal the variables yourself beforehand to localize the failure before calling Execute"],"exampleFix":"// before\nreq := &linear.GraphQLRequest{Query: q, Variables: map[string]interface{}{\"x\": someChan}}\n// after\nvars, err := json.Marshal(map[string]interface{}{\"x\": \"supported-value\"})\nif err != nil { return err } // catch it before the client does\nreq := &linear.GraphQLRequest{Query: q, Variables: parsedVars}","handlingStrategy":"validation","validationCode":"if raw, err := json.Marshal(req); err != nil {\n\treturn fmt.Errorf(\"request not serializable: %w\", err)\n} else if !json.Valid(raw) {\n\treturn fmt.Errorf(\"request marshaled to invalid JSON\")\n}","typeGuard":"func isMarshalable(v interface{}) bool {\n\tvar mErr error\n\t_ = json.Marshal // probe; real check:\n\tmErr = marshalErr(v)\n\treturn mErr == nil\n}\nfunc marshalErr(v interface{}) error {\n\tb, err := json.Marshal(v)\n\t_ = b\n\treturn err\n}","tryCatchPattern":"data, err := client.Execute(ctx, req)\nif err != nil {\n\tif strings.Contains(err.Error(), \"failed to marshal request\") {\n\t\treturn fmt.Errorf(\"bug: request variables unsupported by encoding/json: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Keep GraphQL variables as JSON-safe types (string, number, bool, nil, maps, slices)","Never pass channels, funcs, or cyclic structures as variables","Pre-validate json.RawMessage payloads with json.Valid","Add unit tests that marshal representative request payloads"],"tags":["serialization","json","linear","graphql"],"backgroundTag":"json-marshal-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}