{"record":{"id":"6bc4ad4bc3155b12","repo":"flipped-aurora/gin-vue-admin","slug":"apis-path-method-method-path","errorCode":null,"errorMessage":"apis 数组元素需为 {path,method} 对象或 \"METHOD /path\" 字符串","messagePattern":"apis 数组元素需为 (.+?) 对象或 \"METHOD /path\" 字符串","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mcp/role_api_batch_assigner.go","lineNumber":155,"sourceCode":"\tswitch value := v.(type) {\n\tcase []any:\n\t\tfor _, entry := range value {\n\t\t\tswitch typed := entry.(type) {\n\t\t\tcase map[string]any:\n\t\t\t\tpath, _ := typed[\"path\"].(string)\n\t\t\t\tif strings.TrimSpace(path) == \"\" {\n\t\t\t\t\treturn nil, errors.New(\"apis 数组元素缺少 path 字段\")\n\t\t\t\t}\n\t\t\t\tmethod, _ := typed[\"method\"].(string)\n\t\t\t\tappendItem(path, method)\n\t\t\tcase string:\n\t\t\t\tpath, method, err := parseAPIItemString(typed)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tappendItem(path, method)\n\t\t\tdefault:\n\t\t\t\treturn nil, errors.New(\"apis 数组元素需为 {path,method} 对象或 \\\"METHOD /path\\\" 字符串\")\n\t\t\t}\n\t\t}\n\tcase string:\n\t\ttrimmed := strings.TrimSpace(value)\n\t\tif trimmed == \"\" {\n\t\t\treturn nil, nil\n\t\t}\n\t\t// 兼容只支持字符串参数的 MCP 客户端把 JSON 数组序列化成字符串传入的情况:\n\t\t// 形如 [{\"path\":..,\"method\":..}] 若按逗号切分会碎成垃圾策略,先尝试按 JSON 数组解析\n\t\tif strings.HasPrefix(trimmed, \"[\") {\n\t\t\tvar arr []any\n\t\t\tif err := json.Unmarshal([]byte(trimmed), &arr); err == nil {\n\t\t\t\treturn parseAPIItems(arr)\n\t\t\t}\n\t\t}\n\t\tfor part := range strings.SplitSeq(trimmed, \",\") {\n\t\t\tif strings.TrimSpace(part) == \"\" {\n\t\t\t\tcontinue","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/mcp/role_api_batch_assigner.go#L137-L173","documentation":"parseAPIItems accepts only two element shapes: an object with path/method fields, or a \"METHOD /path\" string parseable by parseAPIItemString. The error is thrown when an element is any other JSON type (number, bool, null, nested array), i.e. the default branch of the type switch.","triggerScenarios":"An apis element like 42, true, null, or [\"/api/x\"] — anything that is neither map[string]any nor string.","commonSituations":"Caller sending a bare path \"/api/user/list\" as a nested array element, string-encoded JSON that arrives still as an array, or items pasted from a loose schema.","solutions":["Format each element as {\"path\":\"/x\",\"method\":\"GET\"} or \"GET /x\"","Remove or fix elements of the wrong type (numbers/bools/null/nested arrays)","Run a client-side type check that rejects items not string-or-object"],"exampleFix":"// before\nargs[\"apis\"] = []any{[]any{\"GET\", \"/api/user/list\"}}\n// after\nargs[\"apis\"] = []any{\"GET /api/user/list\"}","handlingStrategy":"type-guard","validationCode":"const ok = apis.every(a =>\n  typeof a === \"string\" ||\n  (typeof a === \"object\" && a !== null && !Array.isArray(a))\n)\nif (!ok) throw new Error(\"apis 元素类型不合法\")","typeGuard":"function isStringOrApiObj(v: unknown): boolean {\n  if (typeof v === \"string\") return true\n  return typeof v === \"object\" && v !== null && !Array.isArray(v)\n}","tryCatchPattern":"try {\n  await callTool(\"role_api_batch_assigner\", { apis })\n} catch (e) {\n  if (String(e.message).includes(\"需为 {path,method} 对象或\")) {\n    // 重新格式化字符串元素，例如 \"GET /path\"\n  }\n  throw e\n}","preventionTips":["Emit canonical {path,method} objects client-side only; avoid heterogeneous items like strings and numbers","Parse JSON with a parser that preserves types","Always validate array element types before submit, not just the array itself"],"tags":["mcp","validation","type-mismatch","batch-input"],"backgroundTag":"batch-item-schema-mismatch","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}