{"record":{"id":"ab9dd4067c27d3b3","repo":"flipped-aurora/gin-vue-admin","slug":"w-ab9dd4","errorCode":null,"errorMessage":"序列化上游请求失败: %w","messagePattern":"序列化上游请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mcp/http_client.go","lineNumber":181,"sourceCode":"\t}\n\tif !strings.HasPrefix(endpoint, \"/\") {\n\t\tendpoint = \"/\" + endpoint\n\t}\n\n\tbaseURL := upstreamBaseURL()\n\trequestURL, err := url.Parse(baseURL + endpoint)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"构建上游请求地址失败: %w\", err)\n\t}\n\tif len(query) > 0 {\n\t\trequestURL.RawQuery = query.Encode()\n\t}\n\n\tvar reader io.Reader\n\tif body != nil {\n\t\tpayload, err := json.Marshal(body)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"序列化上游请求失败: %w\", err)\n\t\t}\n\t\treader = bytes.NewReader(payload)\n\t}\n\n\ttimeoutCtx, cancel := context.WithTimeout(ctx, requestTimeout())\n\tdefer cancel()\n\n\treq, err := http.NewRequestWithContext(timeoutCtx, method, requestURL.String(), reader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"创建上游请求失败: %w\", err)\n\t}\n\treq.Header.Set(\"Accept\", \"application/json\")\n\treq.Header.Set(upstreamAuthHeader, token)\n\tif body != nil {\n\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\t}\n\t// 链路传播:外部 AI → MCP 进程 → GVA 主服务串成同一条 trace\n\tlogger.InjectTraceHeaders(timeoutCtx, req)","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/mcp/http_client.go#L163-L199","documentation":"When body != nil, doUpstream serializes it with json.Marshal; failure is wrapped as '序列化上游请求失败'. json.Marshal only fails on unsupported types (channels, funcs, cyclic structures, invalid numbers), so this almost always signals a bug in the request payload type.","triggerScenarios":"Request struct contains a channel/func field; cyclic pointer structure; custom MarshalJSON that returns an error; NaN/Inf float values.","commonSituations":"Passing a context-bearing or cyclic object as body; a recently added field of unsupported type; hand-written MarshalJSON with a bug.","solutions":["Look at the wrapped error — json.Marshal names the offending field/type","Remove or replace unsupported field types (channel, func, cyclic refs) in the request struct","Test the payload type with json.Marshal in a unit test","If NaN/Inf floats are possible, sanitize them before passing body"],"exampleFix":"// before\nbody := map[string]any{\"cb\": make(chan int)}\nresp, err := postUpstream[Result](ctx, \"/api/x\", nil, body)\n// after\nbody := map[string]any{\"id\": 123}\nresp, err := postUpstream[Result](ctx, \"/api/x\", nil, body)","handlingStrategy":"validation","validationCode":"func marshalable(v any) error {\n\t_, err := json.Marshal(v)\n\treturn err\n}","typeGuard":null,"tryCatchPattern":"result, err := postUpstream[Data](ctx, \"/api/x\", nil, body)\nif err != nil {\n\tvar marshalErr *json.UnsupportedTypeError\n\tif errors.As(err, &marshalErr) || strings.Contains(err.Error(), \"序列化上游请求失败\") {\n\t\t// inspect body struct for unsupported field types\n\t}\n\treturn err\n}","preventionTips":["Keep request payload types marshal-friendly: no channels, funcs, or cyclic pointers","Sanitize NaN/Inf floats before building payloads","Unit-test json.Marshal on every request struct you introduce","Avoid custom MarshalJSON implementations unless tested"],"tags":["json","serialization","go"],"backgroundTag":"json-marshal-failed","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}