flipped-aurora/gin-vue-admin · error

%s已存在

Error message

%s已存在

What it means

createMarkdownFile returns this error when the target markdown file already exists at skillDir/subDir/cleanName. os.Stat succeeds (err == nil), meaning the path exists, so creation is refused with a message stating what kind of item ('文件' by default) already exists. It is a deliberate duplicate-name guard surfaced to callers CreateResource, CreateReference and CreateTemplate.

Source

Thrown at server/service/system/sys_skills.go:573

func (s *SkillsService) createMarkdownFile(tool, skill, subDir, fileName, defaultContent, label string) (string, string, error) {
	if !isSafeName(skill) {
		return "", "", errors.New("技能名称不合法")
	}
	cleanName, err := buildResourceFileName(fileName)
	if err != nil {
		return "", "", err
	}
	skillDir, err := s.ensureSkillDir(tool, skill)
	if err != nil {
		return "", "", err
	}
	filePath := filepath.Join(skillDir, subDir, cleanName)
	if _, err := os.Stat(filePath); err == nil {
		if label == "" {
			label = "文件"
		}
		return "", "", fmt.Errorf("%s已存在", label)
	}
	if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
		return "", "", err
	}
	content := defaultContent
	if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
		return "", "", err
	}
	return cleanName, content, nil
}

func (s *SkillsService) readSkillFile(tool, skill, subDir, fileName string) (string, error) {
	if !isSafeName(skill) {
		return "", errors.New("技能名称不合法")
	}
	if !isSafeFileName(fileName) {
		return "", errors.New("文件名不合法")
	}

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Pick a different name for the resource/reference/template, or delete/rename the existing file first
  2. Check the skill directory (skillDir/subDir) for the existing file and remove stale leftovers if intentional
  3. Note that name cleaning may map different raw names to the same path — choose a name that stays distinct after cleaning

Example fix

// before
svc.CreateTemplate(skillName, "README") // 文件已存在
// after
if _, err := os.Stat(filepath.Join(skillsDir, skillName, "README.md")); err == nil {
    svc.CreateTemplate(skillName, "README-2")
} else {
    svc.CreateTemplate(skillName, "README")
}
Defensive patterns

Strategy: validation

Validate before calling

// Go: check existence before calling create/create APIs
path := filepath.Join(skillDir, subDir, cleanName)
if _, err := os.Stat(path); err == nil {
    // already exists: choose another name or delete first
}

Type guard

// Go: name-existence guard
func fileExists(path string) bool {
    _, err := os.Stat(path)
    return err == nil
}

Try / catch

name, _, err := svc.CreateTemplate(skillName, candidate)
if err != nil && strings.HasSuffix(err.Error(), "已存在") {
    candidate = candidate + "-2"
    name, _, err = svc.CreateTemplate(skillName, candidate)
}

Prevention

When it happens

Trigger: Calling CreateResource, CreateReference, or CreateTemplate with a name that resolves (after cleaning + subDir) to a path that already exists inside the skill directory.

Common situations: User retries a creation after a prior successful call; two skill items share the same cleaned filename (name normalization collapses distinct inputs to the same path); leftover files from a manual edit or partial migration already occupy the path.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/d7f7c0325f9ec480. Report an issue: GitHub.