larksuite/cli · error

%s: cannot stat %q: %w

Error message

%s: cannot stat %q: %w

What it means

checkOwnerUID verifies that the audited file is owned by the current OS user; it first calls vfs.Stat on the effective path. If that stat fails (file vanished between the symlink resolution and this step, permission denied on a parent directory, or the file is on an unavailable mount), the error is wrapped and returned. Owner checks exist so a file another user controls cannot be injected into secret/command resolution.

Source

Thrown at internal/binding/audit_unix.go:20

// SPDX-License-Identifier: MIT

//go:build !windows

package binding

import (
	"fmt"
	"os"
	"syscall"

	"github.com/larksuite/cli/internal/vfs"
)

// checkOwnerUID verifies the file is owned by the current user.
func checkOwnerUID(path, label string) error {
	stat, err := vfs.Stat(path)
	if err != nil {
		return fmt.Errorf("%s: cannot stat %q: %w", label, path, err)
	}
	sysStat, ok := stat.Sys().(*syscall.Stat_t)
	if !ok {
		return fmt.Errorf("%s: cannot retrieve file owner for %q", label, path)
	}
	if sysStat.Uid != uint32(os.Getuid()) {
		return fmt.Errorf("%s: path %q is owned by uid %d, expected %d",
			label, path, sysStat.Uid, os.Getuid())
	}
	return nil
}

// auditFilePermissions rejects world/group-writable modes (always) and
// world/group-readable modes (unless allowReadableByOthers is true, which
// exec commands typically need for their usual 755 mode).
func auditFilePermissions(effectivePath string, allowReadableByOthers bool, label string) error {
	info, err := vfs.Stat(effectivePath)
	if err != nil {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Check the wrapped cause: ENOENT means the file is gone — recreate it or fix the config path to an existing file
  2. EACCES/EPERM: verify execute/search permission on every parent directory for the current user
  3. Confirm the volume holding the file is mounted (df /path; mount output)
  4. Re-run the command to rule out a transient TOCTOU race

Example fix

// before: path under root while running as alice
cfg.path = "/root/secrets-tool.sh"
// after
cfg.path = "/home/alice/bin/secrets-tool.sh"; chmod 700 /home/alice/bin/secrets-tool.sh
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(resolvedPath); err != nil {
  return fmt.Errorf("pre-flight: cannot access %s: %w", resolvedPath, err)
}

Try / catch

_, err := binding.AssertSecurePath(params)
if err != nil {
  var perr *fs.PathError
  if errors.As(err, &perr) {
    switch {
    case errors.Is(perr.Err, syscall.ENOENT): // restore file or fix path
    case errors.Is(perr.Err, syscall.EACCES): // fix parent dir permissions
    }
  }
  return err
}

Prevention

When it happens

Trigger: Stat fails during the ownership check after symlink resolution and permission audit succeeded: file deleted concurrently, parent directory lost search permission, path on a dead network mount, or the effective path differs subtly (case, trailing whitespace) from the real file.

Common situations: Script removed by a cleanup job while lark-cli runs; config path referencing a file under /root while running as a normal user; NFS/autofs home directories dropped offline; a mis-typed path that only partially matches the real filename.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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