Tencent/WeKnora · error
path %q is outside this install's skill directory (%s); an i
Error message
path %q is outside this install's skill directory (%s); an install may only write its own skill
What it means
resolveSkillFilePath performs a containment check: after joining and Clean-ing the requested path, it must live strictly inside the bound skill directory (not equal to it, not outside its prefix). Otherwise the write could escape the skill installation — including via "..", absolute paths, or symlink-like spellings — so the tool refuses with this error, protecting the principle that an install may only write its own skill.
Source
Thrown at internal/agent/tools/skill_file.go:406
func resolveSkillFilePath(skillDir, requested string) (string, error) {
dir := path.Clean(strings.TrimSpace(skillDir))
if dir == "" || dir == "." || dir == "/" {
return "", fmt.Errorf("this tool is not bound to a skill directory")
}
trimmed := strings.TrimSpace(requested)
if trimmed == "" {
return "", fmt.Errorf("path is required; write a file inside %s", dir)
}
if strings.ContainsRune(trimmed, 0) {
return "", fmt.Errorf("path %q is not a valid file path", requested)
}
candidate := trimmed
if !path.IsAbs(candidate) {
candidate = path.Join(dir, candidate)
}
clean := path.Clean(candidate)
if clean == dir || !strings.HasPrefix(clean, dir+"/") {
return "", fmt.Errorf(
"path %q is outside this install's skill directory (%s); "+
"an install may only write its own skill",
requested, dir,
)
}
return clean, nil
}
View on GitHub (pinned to 988cbb0330)
Solutions
- Pass a path relative to the skill directory that stays inside it (e.g. "docs/readme.md").
- Normalize user/model input (filepath.Clean) and verify the prefix yourself before the call.
- If writing to another skill is genuinely needed, use the tool bound to that skill's directory instead.
Example fix
// before
in := SkillFileInput{Path: "../other-skill/file.txt", Content: data}
// after
p := path.Clean("../other-skill/file.txt")
if !strings.HasPrefix(p, skillDir+"/") {
return fmt.Errorf("refusing to write outside %s", skillDir)
}
in := SkillFileInput{Path: p, Content: data} Defensive patterns
Strategy: validation
Validate before calling
clean := path.Clean(path.Join(skillDir, requested))
if clean == skillDir || !strings.HasPrefix(clean, skillDir+"/") {
return fmt.Errorf("path %q escapes skill directory %s", requested, skillDir)
} Type guard
func insideSkillDir(skillDir, requested string) bool {
clean := path.Clean(path.Join(skillDir, requested))
return clean != skillDir && strings.HasPrefix(clean, skillDir+"/")
} Try / catch
if _, err := tool.Execute(ctx, input); err != nil && strings.Contains(err.Error(), "outside this install's skill directory") {
// clamp the path inside skillDir or reject the operation; do not retry as-is
} Prevention
- Always pass paths relative to the skill directory, never absolute or ../
- Pre-clean and prefix-check untrusted paths before invoking the tool
- Use one bound tool per skill installation instead of crossing directories
When it happens
Trigger: Calling Execute with a path that resolves outside skillDir: an absolute path into another skill, "../" traversal above the skill root, or the skill directory itself (clean == dir).
Common situations: Model attempts to write ../../other-skill/file.txt; caller passes an absolute path from a different install; traversal probing in multi-tenant skill setups.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- invalid path: %w
- invalid file path: %w
- invalid source path: %w
- invalid file name: %w
- invalid source path: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/672178ba6cba1d7c.
Report an issue: GitHub.