{"record":{"id":"cf50fbed8d4ec21a","repo":"flipped-aurora/gin-vue-admin","slug":"s","errorCode":null,"errorMessage":"上游接口业务错误: %s","messagePattern":"上游接口业务错误: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mcp/http_client.go","lineNumber":137,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"请求上游接口失败: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\trawBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"读取响应失败: %w\", err)\n\t}\n\tif resp.StatusCode >= http.StatusBadRequest {\n\t\treturn nil, fmt.Errorf(\"上游接口返回状态码 %d: %s\", resp.StatusCode, string(rawBody))\n\t}\n\n\tvar result upstreamEnvelope[T]\n\tif err := json.Unmarshal(rawBody, &result); err != nil {\n\t\treturn nil, fmt.Errorf(\"解析响应失败: %w\", err)\n\t}\n\tif result.Code != 0 {\n\t\treturn nil, fmt.Errorf(\"上游接口业务错误: %s\", result.Msg)\n\t}\n\treturn &result, nil\n}\n\nfunc getUpstream[T any](ctx context.Context, endpoint string, query url.Values) (*upstreamEnvelope[T], error) {\n\treturn doUpstream[T](ctx, http.MethodGet, endpoint, query, nil)\n}\n\nfunc postUpstream[T any](ctx context.Context, endpoint string, body any) (*upstreamEnvelope[T], error) {\n\treturn doUpstream[T](ctx, http.MethodPost, endpoint, nil, body)\n}\n\nfunc deleteUpstream[T any](ctx context.Context, endpoint string, body any) (*upstreamEnvelope[T], error) {\n\treturn doUpstream[T](ctx, http.MethodDelete, endpoint, nil, body)\n}\n\nfunc doUpstream[T any](ctx context.Context, method, endpoint string, query url.Values, body any) (*upstreamEnvelope[T], error) {\n\ttoken := authTokenFromContext(ctx)","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/mcp/http_client.go#L119-L155","documentation":"The upstream returned a valid envelope but result.Code != 0, i.e. the GVA main service reported a business-level failure; the message includes the upstream's Msg text. This is the application-layer error contract of gin-vue-admin responses ({code:0} means success).","triggerScenarios":"Business rule rejection by the target GVA endpoint: record not found, duplicate key, permission denied at service layer, invalid parameters the handler accepted but service rejected.","commonSituations":"MCP tool calling an endpoint with an ID that no longer exists; user role lacks permission for the operation; validation like unique-username violated; upstream service returning msg in Chinese describing the exact rule.","solutions":["Surface result.Msg to the caller — it describes the exact business rule violated","Verify the parameters/IDs the MCP tool forwarded are still valid in the GVA system","Check the target endpoint's service code for the specific msg string to find the failing rule","If msg indicates permission, adjust the user's role/Casbin policy in GVA admin"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isBusinessError(err error) (msg string, ok bool) {\n\tconst prefix = \"上游接口业务错误: \"\n\tif strings.HasPrefix(err.Error(), prefix) {\n\t\treturn strings.TrimPrefix(err.Error(), prefix), true\n\t}\n\treturn \"\", false\n}","tryCatchPattern":"result, err := postUpstream[Item](ctx, \"/api/item/create\", nil, payload)\nif err != nil {\n\tif msg, ok := isBusinessError(err); ok {\n\t\t// show result.Msg semantics to the end user\n\t\treturn fmt.Errorf(\"operation rejected: %s\", msg)\n\t}\n\treturn err\n}","preventionTips":["Validate IDs/parameters against the live GVA data before calling","Keep the MCP user's roles/Casbin policies aligned with required operations","Map known upstream Msg strings to friendly client messages","Log code+msg pairs to track recurring business-rule rejections"],"tags":["business-logic","api","gin-vue-admin"],"backgroundTag":"upstream-business-code-nonzero","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}