larksuite/cli · error
resolve save path: %w
Error message
resolve save path: %w
What it means
Wraps a validation failure from FileIO.ResolvePath while resolving the save path. The provider rejected the path — typical causes are path traversal, symlink escape, or otherwise invalid target — and the cause is preserved via %w. It guards that saves stay inside the validated workspace.
Source
Thrown at shortcuts/common/runner.go:655
if ctx != nil {
c = ctx.ctx
}
return p.ResolveFileIO(c)
}
return nil
}
// ResolveSavePath resolves a relative path to a validated absolute path via
// FileIO.ResolvePath. It returns an error if no FileIO provider is registered
// or if the path fails validation (e.g. traversal, symlink escape).
func (ctx *RuntimeContext) ResolveSavePath(path string) (string, error) {
fio := ctx.FileIO()
if fio == nil {
return "", fmt.Errorf("no file I/O provider registered")
}
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)
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Fix the input path so it resolves inside the allowed save root (remove ".." or symlink hops)
- Inspect the wrapped cause to see which validation failed and adjust accordingly
- Use runtime.ValidatePath() on candidate paths ahead of time, or let ResolveSavePath normalize by passing a plain relative filename
Example fix
// before
p, err := ctx.ResolveSavePath("../../etc/out.json")
// after
p, err := ctx.ResolveSavePath("out.json") // resolves inside validated save root Defensive patterns
Strategy: validation
Validate before calling
// Reject obviously escaping paths before calling:
if strings.Contains(filepath.ToSlash(path), "..") {
return fmt.Errorf("path must stay inside the save directory")
}
out, err := ctx.ResolveSavePath(path) Try / catch
out, err := ctx.ResolveSavePath(path)
if err != nil {
var ve *errs.ValidationError
if errors.As(errors.Unwrap(err), &ve) {
return fmt.Errorf("invalid save path %q: %w", path, err)
}
return err
} Prevention
- Pass plain relative filenames and let ResolveSavePath normalize them
- Avoid symlinks pointing outside the workspace when choosing save locations
- Pre-validate candidate paths with runtime.ValidatePath()
When it happens
Trigger: ctx.ResolveSavePath("../x") or any path failing ResolvePath validation: ".." escaping the base dir, symlinked paths resolving outside allowed roots, absolute paths in restricted modes, illegal characters.
Common situations: Users passing relative paths with ".." from a different working directory; saving into symlinked folders pointing outside the workspace; paths referencing other users' directories in shared 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
- %s: path must be absolute, got %q
- %s: path %q is a directory, not a file
- path validation failed
- %s: cannot stat %q: %w
- %s: path %q is a symlink (not allowed)
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/55931fff2e6fcbdd.
Report an issue: GitHub.