{"record":{"id":"2d43ccac2edd6b81","repo":"Billionmail/BillionMail","slug":"marshal-lipsync-request-w","errorCode":null,"errorMessage":"marshal lipsync request: %w","messagePattern":"marshal lipsync request: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/video_gen/lipsync.go","lineNumber":77,"sourceCode":"\n// DefaultLipSyncConfig returns config with API key from env.\nfunc DefaultLipSyncConfig(outputDir string) LipSyncConfig {\n\treturn LipSyncConfig{\n\t\tAPIKey:    os.Getenv(\"SYNCLABS_API_KEY\"),\n\t\tOutputDir: outputDir,\n\t}\n}\n\n// BuildLipSyncRequest constructs the HTTP request for lip sync generation.\n// Exported for testing without making API calls.\nfunc BuildLipSyncRequest(cfg LipSyncConfig, req LipSyncRequest) (*http.Request, error) {\n\tif req.Model == \"\" {\n\t\treq.Model = \"sync-1.7.1-beta\"\n\t}\n\n\tbody, err := json.Marshal(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"marshal lipsync request: %w\", err)\n\t}\n\n\thttpReq, err := http.NewRequest(\"POST\", cfg.lipSyncBase()+lipSyncPath, bytes.NewReader(body))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create lipsync request: %w\", err)\n\t}\n\n\thttpReq.Header.Set(\"x-api-key\", cfg.APIKey)\n\thttpReq.Header.Set(\"Content-Type\", \"application/json\")\n\treturn httpReq, nil\n}\n\n// BuildLipSyncStatusRequest constructs the HTTP request to check job status.\n// Exported for testing.\nfunc BuildLipSyncStatusRequest(cfg LipSyncConfig, jobID string) (*http.Request, error) {\n\turl := fmt.Sprintf(\"%s%s/%s\", cfg.lipSyncBase(), lipSyncPath, jobID)\n\thttpReq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/video_gen/lipsync.go#L59-L95","documentation":"BuildLipSyncRequest JSON-encodes the lipsync API request body before constructing the http.Request. If json.Marshal fails on the request struct, the error is wrapped as 'marshal lipsync request: %w'. This is rare for this struct (plain strings/fields), but can happen if unsupported types (channels, funcs, NaN floats) sneak into the payload.","triggerScenarios":"json.Marshal(req) returns an error — req (or a nested field added to it) contains a type JSON cannot encode (e.g. chan, func, or a type with a broken MarshalJSON) or a custom MarshalJSON implementation returns an error.","commonSituations":"A new field with a non-serializable type was added to the lipsync request struct; a custom json.Marshaler on a nested type errors; NaN/Inf float values in dynamically-set fields.","solutions":["Read the wrapped cause to identify the offending field/type in the request struct","Remove or convert non-serializable fields (chan/func/cyclic structures) to JSON-safe types","Add encoding:\"json\" tags or change unsupported field types to strings/numbers","Test with a representative request struct to catch regressions (existing tests already cover headers/body)"],"exampleFix":"// before\ntype LipSyncRequest struct {\n    Callback func() `json:\"callback\"` // unsupported type\n}\n// after\ntype LipSyncRequest struct {\n    CallbackURL string `json:\"callback_url\"`","handlingStrategy":"try-catch","validationCode":"// JSON round-trip check before submitting\nif b, err := json.Marshal(req); err != nil {\n    return fmt.Errorf(\"request not serializable: %w\", err)\n} else { _ = b }","typeGuard":null,"tryCatchPattern":"httpReq, err := video_gen.BuildLipSyncRequest(cfg)\nif err != nil {\n    if strings.Contains(err.Error(), \"marshal lipsync request\") {\n        // unsupported field type in the request struct — fix struct or drop the field\n        return fmt.Errorf(\"request struct contains non-JSON types: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep the lipsync request struct to JSON-safe field types (string, int, bool, slices)","Add json struct tags explicitly for every field","Run the existing TestBuildLipSyncRequest_* tests after changing the request struct","Never embed funcs/chans or custom Marshalers that can fail in request payloads"],"tags":["json","serialization","lipsync","video-gen"],"backgroundTag":"json-marshal-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}