larksuite/cli · error

%s %q resolves outside the current working directory (hint:

Error message

%s %q resolves outside the current working directory (hint: a relative path has to stay inside it; give a full path to reach another allowed root)

What it means

This error enforces the rule that a RELATIVE path passed to `--file`/`--output` must resolve inside the current working directory, even when the resolved location would otherwise be inside a wider allow root (e.g. /tmp). It prevents `../` traversal: a process running under /tmp (CI runners, containers) could otherwise reach sibling sessions' files.

Source

Thrown at internal/vfs/localfileio/path.go:217

	return primary, nil
}

// checkRelativeStaysInCwd holds a relative path to the working directory even
// when a wider allow root would accept where it lands. Naming a full path is a
// deliberate act and the allowlist is the right judge of it; climbing out with
// ".." is not, and the two cannot share one verdict once an allow root is big
// enough to contain the working directory. A process running under /tmp — CI
// runners, containers and agent sandboxes commonly do — would otherwise reach
// a sibling session's files with "../", which the allowlist alone reads as
// still inside /tmp.
func checkRelativeStaysInCwd(flagName, raw, resolved, cwd string) error {
	if filepath.IsAbs(raw) || raw == "~" || strings.HasPrefix(raw, "~/") {
		return nil
	}
	if matchResolved(resolved, newPolicyEntry("the current working directory", cwd)) {
		return nil
	}
	return fmt.Errorf("%s %q resolves outside the current working directory "+
		"(hint: a relative path has to stay inside it; give a full path to reach another allowed root)",
		flagName, raw)
}

// interpretations returns every location this platform could open the argument
// at, most-intended first. They differ only for a leading "~": the first entry
// expands it to the home directory (what a caller using the returned path
// gets), the second keeps it literal (what the OS does with the original
// string).
func interpretations(raw, cwd string) ([]string, error) {
	abs, err := absolutize(raw, cwd)
	if err != nil {
		return nil, err
	}
	out := []string{abs}
	if raw == "~" || strings.HasPrefix(raw, "~/") {
		literal := filepath.Clean(filepath.Join(cwd, raw))
		if literal != abs {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Use a relative path that stays under the current working directory (e.g. sub/file.pdf, not ../file.pdf).
  2. Pass a full absolute path to the target file — a deliberate full path is judged by the allowlist.
  3. cd into the directory containing the file before running the command.
  4. Place the file under ~/files, which is an allowed root for full paths.

Example fix

// before (cwd=/tmp/work)
lark-cli drive upload --file ../shared/report.pdf
// after
lark-cli drive upload --file /tmp/shared/report.pdf
Defensive patterns

Strategy: validation

Validate before calling

// Go: refuse relative paths that climb out of cwd before calling the API
if !filepath.IsAbs(p) && !strings.HasPrefix(p, "~") {
    abs, _ := filepath.Abs(p)
    cwd, _ := os.Getwd()
    if !strings.HasPrefix(abs, cwd+string(filepath.Separator)) {
        return fmt.Errorf("relative path %q must stay inside cwd; pass an absolute path instead", p)
    }
}

Prevention

When it happens

Trigger: Passing a relative path containing `..` that escapes cwd, e.g. `--file ../other/report.pdf` when cwd is /tmp/work and the target resolves to /tmp/other. Absolute paths and `~/...` paths are exempt.

Common situations: Scripts that `cd` into a subdirectory and reference project files via `../`; CI runners whose cwd is inside /tmp; composing commands where the file sits next to (not under) the working directory.

Related errors


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