{"record":{"id":"35074a9515a4c166","repo":"flipped-aurora/gin-vue-admin","slug":"api-s-s-w","errorCode":null,"errorMessage":"创建自动代码 API %s %s 失败: %w","messagePattern":"创建自动代码 API (.+?) (.+?) 失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/auto_code_persistence.go","lineNumber":56,"sourceCode":"\t\t\treturn fmt.Errorf(\"创建自动代码历史失败: %w\", err)\n\t\t}\n\t\treturn nil\n\t})\n}\n\nfunc persistAutoCodeAPIs(tx *gorm.DB, info request.AutoCode, history *request.SysAutoHistoryCreate) error {\n\tif !info.AutoCreateApiToSql || info.OnlyTemplate {\n\t\treturn nil\n\t}\n\tfor _, desired := range info.Apis() {\n\t\tvar existing model.SysApi\n\t\terr := tx.Where(\"path = ? AND method = ?\", desired.Path, desired.Method).First(&existing).Error\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\thistory.ApiIDs = append(history.ApiIDs, existing.ID)\n\t\tcase errors.Is(err, gorm.ErrRecordNotFound):\n\t\t\tif err = tx.Create(&desired).Error; err != nil {\n\t\t\t\treturn fmt.Errorf(\"创建自动代码 API %s %s 失败: %w\", desired.Method, desired.Path, err)\n\t\t\t}\n\t\t\thistory.ApiIDs = append(history.ApiIDs, desired.ID)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"查询自动代码 API %s %s 失败: %w\", desired.Method, desired.Path, err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc persistAutoCodeMenu(\n\ttx *gorm.DB,\n\tinfo request.AutoCode,\n\tpackageTemplate string,\n\thistory *request.SysAutoHistoryCreate,\n) error {\n\tif !info.AutoCreateMenuToSql {\n\t\treturn nil\n\t}","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/auto_code_persistence.go#L38-L74","documentation":"This error is returned by persistAutoCodeAPIs in server/service/system/auto_code_persistence.go when a desired sys_api row (path/method not found in DB) fails to insert via tx.Create. It wraps the GORM error with the API's method and path for identification and aborts the surrounding transaction, so no partial API/history state is persisted.","triggerScenarios":"Persisting auto-code whose API definitions include a path+method pair absent from sys_api, and the INSERT fails: unique-index collision from a concurrent creation of the same path/method, NOT NULL columns missing in the desired struct, DB connection failure, or schema drift renaming/removing sys_api columns.","commonSituations":"Two concurrent code-generation runs racing to insert the same API row; partial migrations leaving sys_api without required columns; over-length or invalid characters in path/description failing strict SQL mode; read-only database or full disk.","solutions":["Unwrap the error to identify the exact DB failure (duplicate key, unknown column, connection error).","For creation races, use an upsert (ON CONFLICT/ON DUPLICATE KEY) or catch duplicate-key errors and re-query to attach the existing ID to history.ApiIDs.","Run migrations/AutoMigrate so sys_api matches the current model.","Validate desired fields (path, method, apiGroup, description) are non-empty and within column limits before insert.","Retry the full persistence transaction on transient DB errors."],"exampleFix":"// before\nif err = tx.Create(&desired).Error; err != nil {\n    return fmt.Errorf(\"创建自动代码 API %s %s 失败: %w\", desired.Method, desired.Path, err)\n}\n\n// after\nif err = tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&desired).Error; err != nil {\n    return fmt.Errorf(\"创建自动代码 API %s %s 失败: %w\", desired.Method, desired.Path, err)\n}\nvar existing system.SysApi\nif err := tx.Where(\"path = ? AND method = ?\", desired.Path, desired.Method).First(&existing).Error; err == nil {\n    history.ApiIDs = append(history.ApiIDs, existing.ID)\n}","handlingStrategy":"validation","validationCode":"func apiExists(db *gorm.DB, path, method string) (uint, bool, error) {\n    var api system.SysApi\n    err := db.Where(\"path = ? AND method = ?\", path, method).First(&api).Error\n    if errors.Is(err, gorm.ErrRecordNotFound) {\n        return 0, false, nil\n    }\n    if err != nil {\n        return 0, false, err\n    }\n    return api.ID, true, nil\n}\n// call before the persistence flow to pre-check each desired API\n","typeGuard":null,"tryCatchPattern":"err := svc.CreateAutoCodeHistory(info)\nif err != nil {\n    var dupErr *mysql.MySQLError\n    if errors.As(errors.Unwrap(err), &dupErr) && dupErr.Number == 1062 {\n        return retryWithBackoff(2, func() error { return svc.CreateAutoCodeHistory(info) })\n    }\n    return fmt.Errorf(\"persist auto code APIs failed: %w\", err)\n}","preventionTips":["Pre-check desired path/method pairs against sys_api before running persistence.","Serialize code-generation jobs per package (lock or queue) to avoid concurrent insert races on sys_api.","Keep sys_api schema migrated and validate required fields (path, method, apiGroup) before insert.","Enable idempotent persistence (upsert or find-or-create) for repeated generation runs.","Wrap persistence in one transaction and retry the whole unit on duplicate-key or transient errors."],"tags":["database","gorm","transaction","api","duplicate-key"],"backgroundTag":"db-insert-failed","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}