{"record":{"id":"64173aaed51e7aec","repo":"flipped-aurora/gin-vue-admin","slug":"error-64173a","errorCode":null,"errorMessage":"技能不存在","messagePattern":"技能不存在","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_skills.go","lineNumber":180,"sourceCode":"\t}\n\treturn nil\n}\n\nfunc (s *SkillsService) Delete(_ context.Context, req request.SkillDeleteRequest) error {\n\tif strings.TrimSpace(req.Tool) == \"\" {\n\t\treturn errors.New(\"工具类型不能为空\")\n\t}\n\tif !isSafeName(req.Skill) {\n\t\treturn errors.New(\"技能名称不合法\")\n\t}\n\tskillDir, err := s.skillDir(req.Tool, req.Skill)\n\tif err != nil {\n\t\treturn err\n\t}\n\tinfo, err := os.Stat(skillDir)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn errors.New(\"技能不存在\")\n\t\t}\n\t\treturn err\n\t}\n\tif !info.IsDir() {\n\t\treturn errors.New(\"技能目录异常\")\n\t}\n\treturn os.RemoveAll(skillDir)\n}\n\nfunc (s *SkillsService) Package(_ context.Context, req request.SkillPackageRequest) (string, []byte, error) {\n\tif strings.TrimSpace(req.Tool) == \"\" {\n\t\treturn \"\", nil, errors.New(\"工具类型不能为空\")\n\t}\n\tif !isSafeName(req.Skill) {\n\t\treturn \"\", nil, errors.New(\"技能名称不合法\")\n\t}\n\n\tskillDir, err := s.skillDir(req.Tool, req.Skill)","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_skills.go#L162-L198","documentation":"SkillsService.Delete resolves the skill directory and stats it; when os.Stat returns an IsNotExist error the skill directory does not exist on disk, so the service returns this error instead of attempting RemoveAll on a missing path.","triggerScenarios":"Calling Delete for a (tool, skill) pair whose directory was already removed, never created, or whose name differs in case/spelling from the on-disk directory.","commonSituations":"Double-clicking delete and submitting twice; skills directory deleted manually or by a git checkout/sync; stale frontend list referencing a renamed skill.","solutions":["Refresh the skill list and confirm the skill still exists before deleting.","Treat this error as idempotent success if the goal is just 'skill gone' (ignore or log it).","Check the skills root path for the tool to confirm the directory name spelling/case."],"exampleFix":"// before: blind delete -> error on second call\nerr := skillsService.Delete(ctx, req)\n// after: tolerate already-deleted\nif err != nil && err.Error() == \"技能不存在\" {\n    err = nil // already removed\n}","handlingStrategy":"try-catch","validationCode":"const list = await api.listSkills(req.Tool)\nif (!list.some(s => s.name === req.Skill)) {\n  // skip delete: already gone\n  return\n}\nawait api.deleteSkill(req)","typeGuard":null,"tryCatchPattern":"err := skillsService.Delete(ctx, req)\nif err != nil && err.Error() == \"技能不存在\" {\n    err = nil // idempotent delete\n}","preventionTips":["Refresh the skill list after any delete to avoid stale rows.","Implement delete as idempotent on the client.","Avoid double-submitting delete buttons (disable while in flight)."],"tags":["filesystem","not-found","stale-state"],"backgroundTag":"resource-not-found","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}