larksuite/cli · error
plugin %q %s filesystem: %w
Error message
plugin %q %s filesystem: %w
What it means
pathError builds the canonical error for every failure of the plugin skill filesystem: an fs.PathError whose Err wraps 'plugin "<owner>" <field> filesystem: <cause>'. It attributes the failure to the plugin (owner) and which overlay field (Base/Overlay) it came from, wrapping the underlying cause so errors.Is on fs.ErrNotExist and friends still works.
Source
Thrown at internal/skillpolicy/pluginfs.go:125
name: name,
isDir: entry.IsDir(),
typ: entry.Type(),
}
}
return safe, nil
}
func (p *pluginFS) recoverPath(op, path string, err *error) {
if value := recover(); value != nil {
*err = p.pathError(op, path, fmt.Errorf("panic: %v", value))
}
}
func (p *pluginFS) pathError(op, path string, cause error) error {
return &fs.PathError{
Op: op,
Path: path,
Err: fmt.Errorf("plugin %q %s filesystem: %w", p.owner, p.field, cause),
}
}
var errorsNilResult = fmt.Errorf("returned nil without an error")
func joinPath(parent, child string) string {
if parent == "." {
return child
}
return parent + "/" + child
}
type pluginFile struct {
fsys *pluginFS
path string
source fs.File
}
View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Unwrap the fs.PathError.Err and inspect the innermost cause with errors.Is/errors.As (fs.ErrNotExist, fs.ErrPermission, etc.).
- Check the plugin named in the message and the Base/Overlay field to find which contributed filesystem is faulty.
- For ErrNotExist causes, verify the requested path exists in the plugin's Overlay with the exact name.
- For plugin authors: make the FS return valid errors and never (nil, nil).
Example fix
// handling the wrapped error as a caller
file, err := protected.Open("my-skill/SKILL.md")
if err != nil {
var perr *fs.PathError
if errors.As(err, &perr) && errors.Is(perr.Err, fs.ErrNotExist) {
// skill missing from plugin overlay
}
} Defensive patterns
Strategy: type-guard
Type guard
func AsPluginPathError(err error) (*fs.PathError, bool) {
var perr *fs.PathError
if errors.As(err, &perr) && strings.Contains(perr.Err.Error(), "plugin ") {
return perr, true
}
return nil, false
} Try / catch
if err != nil {
var perr *fs.PathError
if errors.As(err, &perr) {
// perr.Op, perr.Path attribute the failing operation
// errors.Is(perr.Err, fs.ErrNotExist) still works through the wrap
}
} Prevention
- Always inspect with errors.As to *fs.PathError, not string matching.
- Use errors.Is for sentinel causes like fs.ErrNotExist/fs.ErrPermission.
- Log the plugin owner and Base/Overlay field from the message when filing bugs.
- Never swallow the error; the wrap preserves the original cause.
When it happens
Trigger: Any Open/Stat/ReadFile/ReadDir/Read/Close on the protected plugin FS fails: the plugin returns an error, returns nil with nil error (errorsNilResult), or panics (converted by the recovery boundaries).
Common situations: A plugin Overlay lacks a requested SKILL.md path; a plugin FS returns fs.ErrPermission; a plugin's directory entries contain a nil DirEntry; a host-integrator's Base FS is misconfigured.
Related errors
- returned nil without an error
- Args field %s (--%s): %w
- array item: %w
- %s field %s (%s): %w
- Invalid column: {column!r}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/39aac5ba2eef3b65.
Report an issue: GitHub.