{"record":{"id":"78a32da097c69fe2","repo":"flipped-aurora/gin-vue-admin","slug":"d-d","errorCode":null,"errorMessage":"单次批量授权不能超过 %d 条,收到 %d 条","messagePattern":"单次批量授权不能超过 (.+?) 条,收到 (.+?) 条","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/mcp/role_api_batch_assigner.go","lineNumber":79,"sourceCode":"\t)\n}\n\nfunc (r *RoleAPIBatchAssigner) Handle(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n\targs := request.GetArguments()\n\n\tauthorityID, err := parseAuthorityID(args[\"authorityId\"])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\titems, err := parseAPIItems(args[\"apis\"])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(items) == 0 {\n\t\treturn nil, errors.New(\"apis 参数是必需的,且至少包含一条\")\n\t}\n\tif len(items) > orgBatchLimit {\n\t\treturn nil, fmt.Errorf(\"单次批量授权不能超过 %d 条,收到 %d 条\", orgBatchLimit, len(items))\n\t}\n\n\tcurrentResp, err := postUpstream[map[string][]systemReq.CasbinInfo](ctx, \"/casbin/getPolicyPathByAuthorityId\", map[string]any{\n\t\t\"authorityId\": authorityID,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"获取角色当前API权限失败: %w\", err)\n\t}\n\n\tupdated := currentResp.Data[\"paths\"]\n\tresult := roleAPIBatchAssignResponse{Success: true, AuthorityID: authorityID}\n\tanyAdded := false\n\tfor _, item := range items {\n\t\tvar added bool\n\t\tupdated, added = appendPolicyIfMissing(updated, item.Path, item.Method)\n\t\tpath, method := normalizePolicy(item.Path, item.Method)\n\t\tresult.Items = append(result.Items, batchAPIItemResult{\n\t\t\tPath:          path,","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/mcp/role_api_batch_assigner.go#L61-L97","documentation":"Client-side batch-size guard in role_api_batch_assigner. orgBatchLimit (50) caps how many API policy items a single write tool call may contain, to limit blast radius of mistakes. Exceeding it is rejected before any upstream call is made.","triggerScenarios":"Calling the batch API assignment tool with an apis array of more than 50 entries (len(items) > orgBatchLimit).","commonSituations":"Importing a whole role's permission matrix in one call; scripting a loop that accumulates all APIs into a single invocation; copying a large casbin export into one request.","solutions":["Split the apis array into chunks of at most 50 and call the tool once per chunk","Reduce the item list to only the APIs actually missing for the role","Use role-level bulk endpoints (e.g. updateCasbin directly) if you truly need a single large write, with your own safeguards"],"exampleFix":"// before\n{\"authorityId\": 8881, \"apis\": [ ...300 items... ]}\n// after\n{\"authorityId\": 8881, \"apis\": [ ...first 50 items... ]} // repeat for each chunk","handlingStrategy":"validation","validationCode":"const orgBatchLimit = 50\nif len(apis) > orgBatchLimit {\n    chunks := (len(apis) + orgBatchLimit - 1) / orgBatchLimit\n    for i := 0; i < chunks; i++ {\n        end := min((i+1)*orgBatchLimit, len(apis))\n        assignBatch(authorityID, apis[i*orgBatchLimit:end])\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Chunk large permission imports into ≤50-item calls before invoking","Deduplicate and filter to only missing policies to shrink batches","For very large writes, use a scripted loop rather than one giant call"],"tags":["validation","batch-limit","casbin"],"backgroundTag":"batch-size-limit-exceeded","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}