Tencent/WeKnora · error · ErrInvalidSkillName
ErrInvalidSkillName
ErrInvalidSkillName
Error message
%w %q
What it means
SkillDirFor maps a skill name (from SKILL.md) to its directory under the skills image root, but only if the name passes IsValidSkillName. This sentinel-wrapped error (errors.Is-able via ErrInvalidSkillName) is thrown for names that could escape the skills directory — empty names, path separators, "..", slashes, etc.
Source
Thrown at internal/sandbox/skill_paths.go:47
// separator are rejected so install/exec cannot walk out of the skills root.
func IsValidSkillName(name string) bool {
name = strings.TrimSpace(name)
if name == "" || name == "." || name == ".." {
return false
}
if strings.ContainsAny(name, "/\\\x00") {
return false
}
return path.Base(path.Clean(name)) == name
}
// SkillDirFor returns the image directory of a skill. The key is the skill
// name from SKILL.md: that is what the installer writes, and what the agent
// is told to execute. The database id stays a row key and is not part of
// the path.
func SkillDirFor(skillName string) (string, error) {
if !IsValidSkillName(skillName) {
return "", fmt.Errorf("%w %q", ErrInvalidSkillName, skillName)
}
return path.Join(SkillsImageRoot, skillName), nil
}
// SkillRequirementsPath is where the installer agent writes what the skill
// needs at run time. It lives inside the skill's own directory so it travels
// with the skill into the snapshot, and it is a file rather than a tool call
// on purpose: the agent reads a third-party SKILL.md, so nothing it produces
// may reach the database except as bytes the server parses and validates.
//
// An invalid skill name yields an empty path, which every caller treats as
// "no declaration": the name is already validated before an install starts,
// and a best-effort read is not a place to fail an install.
func SkillRequirementsPath(skillName string) string {
dir, err := SkillDirFor(skillName)
if err != nil {
return ""
}View on GitHub (pinned to 988cbb0330)
Solutions
- Validate the name with IsValidSkillName before use and reject/repair bad values at ingestion time.
- Normalize the stored skill name to the allowed charset (letters/digits/dashes per the validator) and re-save it.
- Check errors.Is(err, sandbox.ErrInvalidSkillName) and surface a user-facing 'invalid skill name' message instead of a raw path error.
Example fix
// before
dir, err := sandbox.SkillDirFor(userInput) // may be "../x"
// after
if !sandbox.IsValidSkillName(userInput) {
return fmt.Errorf("invalid skill name %q", userInput)
}
dir, err := sandbox.SkillDirFor(userInput) Defensive patterns
Strategy: validation
Validate before calling
if !sandbox.IsValidSkillName(name) {
return fmt.Errorf("invalid skill name %q", name)
} Type guard
func validSkillName(name string) bool { return sandbox.IsValidSkillName(name) } Try / catch
dir, err := sandbox.SkillDirFor(name)
if errors.Is(err, sandbox.ErrInvalidSkillName) {
return fmt.Errorf("skill %q has an invalid name; fix SKILL.md", name)
} Prevention
- Validate skill names at ingestion/install time, not at use time.
- Never build skill paths from URL segments or raw user input.
- Run a migration check over stored skill names after library upgrades.
When it happens
Trigger: Calling SkillDirFor, or any of its callers (DiscoverSkills, LoadSkillInstructions, LoadSkillFile, GetSkillBasePath, RemoteScriptPath, relativeSkillFileFromImagePath) with a skillName failing IsValidSkillName — e.g. "", "../escape", "a/b", or names with illegal characters.
Common situations: Storing skill names from user input or a database with slashes/whitespace; older records predating the naming rule; hand-edited SKILL.md name fields; constructing skill paths from URL segments.
Related errors
- invalid file path: %w
- invalid file name: %w
- invalid source path: %w
- invalid file path: %w
- object key contains path traversal
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/dace1ec2cb177e5b.
Report an issue: GitHub.