Tencent/WeKnora · error
this tool is not bound to a skill directory
Error message
this tool is not bound to a skill directory
What it means
resolveSkillFilePath rejects a skillDir that is empty, ".", or "/" after Clean+TrimSpace, because the skill-file tool must be bound to a concrete skill installation directory to safely scope file writes. Returning this error means the tool instance was constructed without a valid skill directory binding, not that the requested path itself is bad.
Source
Thrown at internal/agent/tools/skill_file.go:391
}
// Cleanup releases any resources.
func (t *EditSkillFileTool) Cleanup(ctx context.Context) error {
return nil
}
// resolveSkillFilePath turns a model-supplied path into an absolute path
// proven to sit inside skillDir.
//
// A relative path is resolved against skillDir, which is what the model
// reaches for after being told the directory once. Everything is then cleaned
// and re-checked against the prefix, so "..", a symlink-looking spelling or an
// absolute path into a neighbouring skill all fail here rather than reaching
// the image. The directory itself is refused: it is not a file.
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,View on GitHub (pinned to 988cbb0330)
Solutions
- Construct/configure the tool with the concrete installed skill directory path.
- Fail earlier at setup if the skill directory cannot be resolved instead of registering the tool.
- In tests, point the tool at a temporary fixture skill directory.
Example fix
// before
tool := tools.NewSkillFileTool("") // unbound
// after
skillDir := filepath.Join(cfg.SkillsRoot, install.Name)
if skillDir == "" {
return errors.New("cannot register skill file tool: no install dir")
}
tool := tools.NewSkillFileTool(skillDir) Defensive patterns
Strategy: type-guard
Validate before calling
d := path.Clean(strings.TrimSpace(skillDir))
if d == "" || d == "." || d == "/" {
return errors.New("skill file tool requires a concrete skill directory")
} Type guard
func isBoundToSkillDir(dir string) bool {
d := path.Clean(strings.TrimSpace(dir))
return d != "" && d != "." && d != "/"
} Try / catch
out, err := tool.Execute(ctx, input)
if err != nil && strings.Contains(err.Error(), "not bound to a skill directory") {
// resolve the install dir, rebind the tool, then retry once
} Prevention
- Resolve and verify the skill install directory before constructing the tool
- Skip tool registration when the skill directory cannot be resolved
- Use real fixture directories in tests instead of empty strings
When it happens
Trigger: Calling Execute on a skill-file tool whose skillDir binding is empty/missing, or explicitly "." or "/" — e.g. the tool was created before the skill install directory was resolved.
Common situations: Tool constructed with a zero-value config; skill installation lookup failed earlier and an empty dir was propagated; tests instantiating the tool without a fixture directory.
Related errors
- path is required; write a file inside %s
- custom agent configuration is required for agent QA
- summary model (model_id) is not configured in custom agent s
- rerank model is not configured: please set rerank_model_id o
- JWKS document contains no keys
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/e3655a77301c0c32.
Report an issue: GitHub.