{"record":{"id":"60d1e839ae0046c1","repo":"flipped-aurora/gin-vue-admin","slug":"apiid","errorCode":null,"errorMessage":"apiId不能为空","messagePattern":"apiId不能为空","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/plugin/ai/service/sys_cli.go","lineNumber":138,"sourceCode":"\treturn res, nil\n}\n\nfunc (s *cliService) GetCliDetail(ctx context.Context, req autoReq.FindSysCliRequest) (autoRes.SysCliDetailResponse, error) {\n\treturn s.getCliDetailByID(ctx, req.ID)\n}\n\nfunc (s *cliService) AddCliApis(ctx context.Context, req autoReq.AddSysCliApisRequest) (autoRes.SysCliDetailResponse, error) {\n\tif _, err := s.getSysCliByID(ctx, req.CliID); err != nil {\n\t\treturn autoRes.SysCliDetailResponse{}, err\n\t}\n\tif len(req.Bindings) == 0 {\n\t\treturn s.getCliDetailByID(ctx, req.CliID)\n\t}\n\tapiIDs := make([]uint, 0, len(req.Bindings))\n\tseen := make(map[uint]struct{}, len(req.Bindings))\n\tfor _, binding := range req.Bindings {\n\t\tif binding.ApiID == 0 {\n\t\t\treturn autoRes.SysCliDetailResponse{}, errors.New(\"apiId不能为空\")\n\t\t}\n\t\tif _, ok := seen[binding.ApiID]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tseen[binding.ApiID] = struct{}{}\n\t\tapiIDs = append(apiIDs, binding.ApiID)\n\t}\n\tif err := s.ensureApisExist(ctx, apiIDs); err != nil {\n\t\treturn autoRes.SysCliDetailResponse{}, err\n\t}\n\tif err := global.GVA_DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {\n\t\tfor _, item := range req.Bindings {\n\t\t\tvar existing autoModel.SysCliApi\n\t\t\terr := tx.Unscoped().Where(\"cli_id = ? AND api_id = ?\", req.CliID, item.ApiID).First(&existing).Error\n\t\t\tif errors.Is(err, gorm.ErrRecordNotFound) {\n\t\t\t\tentity := autoModel.SysCliApi{CliID: req.CliID, ApiID: item.ApiID, CommandName: strings.TrimSpace(item.CommandName), CommandDesc: strings.TrimSpace(item.CommandDesc), ParamsOverride: strings.TrimSpace(item.ParamsOverride), ApiBrief: strings.TrimSpace(item.ApiBrief), ResponseOverride: strings.TrimSpace(item.ResponseOverride), Enabled: item.Enabled, Sort: item.Sort}\n\t\t\t\tif err := tx.Create(&entity).Error; err != nil {\n\t\t\t\t\treturn err","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/plugin/ai/service/sys_cli.go#L120-L156","documentation":"AddCliApis validates each binding in req.Bindings: a binding whose ApiID is 0 (the zero value for uint) is rejected with this error because an API binding without an API id is meaningless. Valid ids are deduplicated via the seen map and collected into apiIDs for the existence check.","triggerScenarios":"Calling AddCliApis with a Bindings slice containing an element where ApiID is unset/zero, e.g. a binding that only carries other fields (params/order) but no ApiID, or a client that failed to populate the id.","commonSituations":"Frontend building binding rows from an API picker where the selection was cleared but the row kept; JSON payloads using a string key like \"apiId\" that does not match the Go field so it unmarshals to 0; batch scripts looping over partially populated records.","solutions":["Ensure every element of req.Bindings has a non-zero ApiID before calling","Filter out bindings with ApiID == 0 client-side","Fix JSON field names so ApiID actually deserializes","Validate the payload with a quick loop before the service call"],"exampleFix":"// before\nbindings := []autoReq.SysCliApiBinding{{Params: \"{}\"}, {ApiID: 3}}\ncliService.AddCliApis(ctx, autoReq.AddSysCliApisRequest{CliID: 1, Bindings: bindings})\n// after\nvalid := bindings[:0]\nfor _, b := range bindings {\n    if b.ApiID != 0 { valid = append(valid, b) }\n}\ncliService.AddCliApis(ctx, autoReq.AddSysCliApisRequest{CliID: 1, Bindings: valid})","handlingStrategy":"validation","validationCode":"for i, b := range req.Bindings {\n    if b.ApiID == 0 {\n        return fmt.Errorf(\"bindings[%d].apiId is required\", i)\n    }\n}","typeGuard":"func allBindingsValid(bindings []autoReq.SysCliApiBinding) bool {\n    for _, b := range bindings {\n        if b.ApiID == 0 { return false }\n    }\n    return true\n}","tryCatchPattern":"detail, err := cliService.AddCliApis(ctx, req)\nif err != nil {\n    if err.Error() == \"apiId不能为空\" {\n        return fmt.Errorf(\"every binding needs an apiId; check rows with empty API selection\")\n    }\n    return err\n}","preventionTips":["Filter zero-ApiID bindings out of the payload before sending","Verify JSON keys match the Go struct tags so ids deserialize","Disable the submit button until every binding row has an API selected","Log the raw payload when this error occurs to spot deserialization issues"],"tags":["validation","go","plugin-ai","binding"],"backgroundTag":"required-field-missing","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}