larksuite/cli · warning
%s: %w
Error message
%s: %w
What it means
WrapOpenError wraps a FileIO.Open/Stat error with a caller-provided message prefix. If the underlying error matches fileio.ErrPathValidation (unsafe path: absolute, traversal, symlink escape), it uses pathMsg; otherwise it uses readMsg (typically 'cannot read file'). The original error is preserved via %w so errors.Is/As still work.
Source
Thrown at shortcuts/common/runner.go:670
}
resolved, err := fio.ResolvePath(path)
if err != nil {
return "", fmt.Errorf("resolve save path: %w", err)
}
if resolved == "" {
return "", fmt.Errorf("resolve save path: empty result for %q", path)
}
return resolved, nil
}
// WrapOpenError matches a FileIO.Open/Stat error and wraps it with the
// caller-provided message prefix.
func WrapOpenError(err error, pathMsg, readMsg string) error {
if err == nil {
return nil
}
if errors.Is(err, fileio.ErrPathValidation) {
return fmt.Errorf("%s: %w", pathMsg, err)
}
return fmt.Errorf("%s: %w", readMsg, err)
}
// WrapInputStatErrorTyped wraps a FileIO.Stat/Open error for input file
// validation, returning a typed validation error with the appropriate message:
// - Path validation failures → "unsafe file path: ..."
// - Other errors → readMsg prefix (default "cannot read file")
//
// Pass an optional readMsg to override the non-path-validation message prefix.
func WrapInputStatErrorTyped(err error, readMsg ...string) error {
if err == nil {
return nil
}
if errors.Is(err, fileio.ErrPathValidation) {
return errs.NewValidationError(errs.SubtypeInvalidArgument, "unsafe file path: %s", err).
WithCause(err)
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Check the wrapped cause: errors.Is(err, fileio.ErrPathValidation) distinguishes unsafe paths from read failures
- For unsafe paths, pass a workspace-relative path without '..' segments or symlinks escaping the workdir
- For read failures, verify the file exists and is readable before invoking the command
Example fix
// before
err := common.WrapOpenError(err, "invalid --input path", "cannot read --input file")
// after (guard at call site)
if err := ctx.ValidatePath(input); err != nil { return err } // fails early with clear message Defensive patterns
Strategy: validation
Validate before calling
if err := ctx.ValidatePath(inputPath); err != nil { return err } // fails early before Open Type guard
func isUnsafePathErr(err error) bool { return errors.Is(err, fileio.ErrPathValidation) } Try / catch
if err != nil { wrapped := common.WrapOpenError(err, "invalid path", "cannot read file"); if errors.Is(wrapped, fileio.ErrPathValidation) { /* advise relative path */ } return wrapped } Prevention
- Always pass workspace-relative input paths
- Validate with ctx.ValidatePath before opening
- Never embed '..' or absolute paths in input flags
When it happens
Trigger: Any shortcut call site that validates an input file and passes the resulting error to common.WrapOpenError: path rejected by SafeInputPath validation (pathMsg branch), or Open/Stat failure such as missing file or permission denied (readMsg branch).
Common situations: User passes --file with '../etc/passwd' or an absolute path (path validation); user passes a nonexistent or unreadable file; CI environment lacks the workspace file.
Related errors
- invalid file path %q: %w
- path validation failed
- %s: path must be absolute, got %q
- %s: cannot stat %q: %w
- %s: path %q is a directory, not a file
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/decad37332e9190b.
Report an issue: GitHub.