larksuite/cli · error

path validation failed

Error message

path validation failed

What it means

ErrPathValidation is the sentinel error in extension/fileio indicating a file path failed security validation (traversal, absolute paths, control characters, symlink escape, etc.). PathValidationError wraps it plus the original error so errors.Is matches both the sentinel and the OS cause. Callers like internal/client/response.go classify it as a typed ValidationError (SubtypeInvalidArgument, param --output).

Source

Thrown at extension/fileio/errors.go:10

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT

package fileio

import "errors"

// ErrPathValidation indicates the path failed security validation
// (traversal, absolute, control chars, symlink escape, etc.).
var ErrPathValidation = errors.New("path validation failed")

// PathValidationError wraps a path validation error.
// errors.Is(err, ErrPathValidation) returns true.
// errors.Is(err, <original OS error>) also works via the chain.
type PathValidationError struct {
	Err error // original error
}

func (e *PathValidationError) Error() string { return e.Err.Error() }
func (e *PathValidationError) Unwrap() []error {
	return []error{ErrPathValidation, e.Err}
}

// MkdirError indicates parent directory creation failed.
// Use errors.As(err, &fileio.MkdirError{}) to match.
type MkdirError struct {
	Err error
}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Sanitize the target path: make it relative to the allowed root and remove '..' segments.
  2. Read the wrapped original error (errors.Is/Unwrap chain) for the exact violation.
  3. Resolve symlinks and ensure the final path stays within the permitted root.
  4. Strip control characters and normalize separators before passing the path.

Example fix

// before
out := filepath.Join(userInput, "../../etc/passwd")
fileio.SaveResponse(ctx, resp, out)
// after
clean := filepath.Clean(filepath.Join(rootDir, filepath.FromSlash(userInput)))
if !strings.HasPrefix(clean, rootDir) { return fmt.Errorf("path escapes root") }
fileio.SaveResponse(ctx, resp, clean)
Defensive patterns

Strategy: validation

Validate before calling

// Go: pre-validate before calling fileio
func safePath(root, p string) (string, error) {
	clean := filepath.Clean(filepath.Join(root, p))
	if !strings.HasPrefix(clean, filepath.Clean(root)+string(os.PathSeparator)) {
		return "", fmt.Errorf("path escapes root: %s", p)
	}
	for _, r := range clean {
		if unicode.IsControl(r) {
			return "", fmt.Errorf("control character in path")
		}
	}
	return clean, nil
}

Type guard

func asSafePath(err error) (string, bool) {
	var pve *fileio.PathValidationError
	if errors.As(err, &pve) && errors.Is(err, fileio.ErrPathValidation) {
		return pve.Err.Error(), true
	}
	return "", false
}

Try / catch

// Go: classify and recover
if err := fileio.SaveResponse(ctx, resp, out); err != nil {
	if errors.Is(err, fileio.ErrPathValidation) {
		err = errs.NewValidationError(errs.SubtypeInvalidArgument, "%v", err).WithParam("--output")
		// prompt user for a corrected path and retry once
	}
	return err
}

Prevention

When it happens

Trigger: Calling fileio Save/open APIs (e.g. SaveResponse, wrapInputFileError paths) with a path containing '..', absolute paths when disallowed, control characters, or a symlink escaping the allowed root; classifySaveErr maps any error matching this sentinel to the typed validation error.

Common situations: Download/save targets built from untrusted input; temp-dir handling with symlinked /tmp; tests or plugins constructing paths with user data; host environment where the workspace root is a symlink.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/7d4a646d718a72b2. Report an issue: GitHub.