{"record":{"id":"82fba21de2ef7e4f","repo":"flipped-aurora/gin-vue-admin","slug":"apis","errorCode":null,"errorMessage":"apis 参数是必需的,且至少包含一条","messagePattern":"apis 参数是必需的,且至少包含一条","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mcp/role_api_batch_assigner.go","lineNumber":76,"sourceCode":"\t\t\tmcp.Required(),\n\t\t\tmcp.Description(\"API列表，JSON数组[{path,method}]或逗号分隔字符串\\\"METHOD /path, ...\\\"\"),\n\t\t),\n\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)","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/mcp/role_api_batch_assigner.go#L58-L94","documentation":"RoleAPIBatchAssigner.Handle parses 'apis' via parseAPIItems and requires the resulting list to contain at least one item. The error is thrown when 'apis' is missing, resolves to an empty array, or is an empty/whitespace string (which parseAPIItems treats as nil, hitting the length check).","triggerScenarios":"Calling with no 'apis', apis = [], apis = \"\" or \"   \", or apis parsing to an empty item list.","commonSituations":"Batch authorization flow with no APIs selected; UI submit where a method-only field was provided; upstream form sending empty string instead of omitting the field.","solutions":["Provide an 'apis' array containing at least one {path,method} object or \"METHOD /path\" string","Verify the submitting UI/caller actually includes selected items","Check len(apis) > 0 client-side before calling"],"exampleFix":"// before\nargs[\"apis\"] = []\n// after\nargs[\"apis\"] = []any{map[string]any{\"path\": \"/api/user/list\", \"method\": \"GET\"}}","handlingStrategy":"validation","validationCode":"const apis = args[\"apis\"]\nif (!Array.isArray(apis) || apis.length === 0) {\n  throw new Error(\"apis 参数是必需的,且至少包含一条\")\n}","typeGuard":"function hasItems(v: unknown): v is unknown[] {\n  return Array.isArray(v) && v.length > 0\n}","tryCatchPattern":"try {\n  await callTool(\"role_api_batch_assigner\", { apis })\n} catch (e) {\n  if (String(e.message).includes(\"apis 参数\")) {\n    // 引导用户至少选择一条 API\n  }\n  throw e\n}","preventionTips":["Check for empty selections early in UI submit handlers","Filter out blank items before submitting","Distinguish between omitted field and empty string — both fail"],"tags":["mcp","validation","empty-array"],"backgroundTag":"empty-required-collection","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}