siyuan-note/siyuan · error

invalid skill name: %s

Error message

invalid skill name: %s

What it means

Thrown by validateSkillName (kernel/util/skill.go:108) when the supplied skill name is the empty string, ".", or "..". It is the first of three guards in validateSkillName and blocks trivially empty or self/parent-referential names before any filesystem operation. ReadSkill/SaveSkill/RemoveSkill/RenameSkill all run it first.

Source

Thrown at kernel/util/skill.go:108

		b, err := filelock.ReadFile(skillMdPath)
		if err != nil {
			continue
		}
		fm, body := parseSkillFrontmatter(string(b))
		skillName := fm["name"]
		if skillName == "" {
			skillName = e.Name()
		}
		if strings.EqualFold(skillName, name) || strings.EqualFold(e.Name(), name) {
			return body
		}
	}
	return ""
}

func validateSkillName(name string) error {
	if name == "" || name == "." || name == ".." {
		return fmt.Errorf("invalid skill name: %s", name)
	}
	if strings.ContainsAny(name, `/\`) {
		return fmt.Errorf("invalid skill name: %s", name)
	}
	dir := SkillsDir()
	abs := filepath.Join(dir, name)
	if !gulu.File.IsSubPath(dir, abs) {
		return fmt.Errorf("invalid skill name: %s", name)
	}
	return nil
}

func ReadSkill(name string) (string, error) {
	if err := validateSkillName(name); err != nil {
		return "", err
	}
	skillMdPath := filepath.Join(SkillsDir(), name, "SKILL.md")
	b, err := filelock.ReadFile(skillMdPath)

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Validate the name on the caller side before invoking the skill API (non-empty, not "." or "..").
  2. Disable the submit button until a non-empty name is entered in the UI.
  3. Audit the request payload to confirm the name field is being serialized.

Example fix

// before
err := util.SaveSkill(req.Name, req.Content)

// after
name := strings.TrimSpace(req.Name)
if name == "" || name == "." || name == ".." {
    return errors.New("skill name must be a non-empty, non-traversal name")
}
err := util.SaveSkill(name, req.Content)
Defensive patterns

Strategy: validation

Validate before calling

name := strings.TrimSpace(req.Name)
if name == "" || name == "." || name == ".." {
    return errors.New("skill name must be a non-empty value other than '.' or '..'")
}

Try / catch

if err := util.ReadSkill(name); err != nil {
    if strings.HasPrefix(err.Error(), "invalid skill name") {
        // input-validation failure; surface to user, do not retry unchanged
        return userFacingValidationError{err}
    }
    return err
}

Prevention

When it happens

Trigger: Calling ReadSkill(""), SaveSkill(".", ...), or RemoveSkill("..") — typically a caller bug that passed an unset/zero-value name, or a UI form that submitted before a name was entered.

Common situations: Frontend sends a skill API request without filling the name field; a script iterates a list and forwards an empty entry; a rename operation passed an empty newName.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/5e257eff0e2e4dce. Report an issue: GitHub.