larksuite/cli · error
%q has an empty relative path
Error message
%q has an empty relative path
What it means
A trailing slash (e.g. "auth/") leaves the path component empty after strings.Cut, which would ambiguously mean "the skill's SKILL.md" while the user clearly asked for a path. Parse rejects this exact shape rather than silently treating it as no path.
Source
Thrown at internal/skillref/ref.go:35
type Ref struct {
Skill string
Path string
}
// Parse parses the "name[/relative/path]" form accepted by `skills read`.
func Parse(raw string) (Ref, error) {
if raw == "" {
return Ref{}, fmt.Errorf("skill reference is empty")
}
skill, path, _ := strings.Cut(raw, "/")
if !ValidSkillName(skill) {
return Ref{}, fmt.Errorf("%q has invalid skill name %q", raw, skill)
}
if path != "" && (!fs.ValidPath(path) || path == "." || strings.Contains(path, `\`)) {
return Ref{}, fmt.Errorf("%q has invalid relative path %q", raw, path)
}
if path == "" && strings.HasSuffix(raw, "/") {
return Ref{}, fmt.Errorf("%q has an empty relative path", raw)
}
return Ref{Skill: skill, Path: path}, nil
}
// ValidSkillName reports whether name can identify a top-level skill
// directory. Keep this rule aligned with the skill-tree manifest validator.
func ValidSkillName(name string) bool {
return name != "" && name != "." && name != ".." && !strings.ContainsAny(name, `/\`)
}
// String returns the canonical "name[/relative/path]" form.
func (r Ref) String() string {
if r.Path == "" {
return r.Skill
}
return r.Skill + "/" + r.Path
}
View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Drop the trailing slash: use "auth" (for SKILL.md) or "auth/references/tokens.md" (for a file).
- Trim trailing "/" with strings.TrimRight(raw, "/") before Parse when input is assembled.
- If the intent was the skill root, omit the slash entirely — empty Path already means SKILL.md.
- Fix the templating/variable so an empty subpath component is skipped instead of leaving a dangling slash.
Example fix
// before
ref, err := skillref.Parse(fmt.Sprintf("%s/%s", skill, subpath)) // "auth/"
// after
raw := skill
if subpath != "" {
raw = skill + "/" + subpath
}
ref, err := skillref.Parse(raw) Defensive patterns
Strategy: validation
Validate before calling
raw = strings.TrimRight(raw, "/")
if raw == "" { return errors.New("empty reference") }
ref, err := skillref.Parse(raw) Try / catch
if err != nil && strings.Contains(err.Error(), "empty relative path") {
ref, err = skillref.Parse(strings.TrimRight(raw, "/"))
} Prevention
- Skip empty subpath components when templating "<skill>/<subpath>"
- Trim trailing slashes from path inputs at the CLI boundary
- Remember empty Path already means the skill's SKILL.md — no trailing slash needed
When it happens
Trigger: Parse("auth/") — trailing slash with no path after it. Common when a base path variable ends with "/" and is concatenated with an empty suffix.
Common situations: Shell scripts building "${SKILL}/${SUBPATH}" where SUBPATH is empty; tab-completion or copy of a directory URL/path including the trailing slash.
Related errors
- skill reference is empty
- %q has invalid skill name %q
- %w: source %q: %w
- name must not be empty
- name %q must not include leading dashes
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/ab0448cf98f3122d.
Report an issue: GitHub.