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
- Check the wrapped cause: ENOENT means the file is gone — recreate it or fix the config path to an existing file
- EACCES/EPERM: verify execute/search permission on every parent directory for the current user
- Confirm the volume holding the file is mounted (df /path; mount output)
- 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
- Verify the file exists with ls -l before configuring it
- Use absolute paths of real files, not near-miss spellings
- Keep the file on a mounted, local-reachable volume
- Avoid running the CLI while cleanup jobs may delete the file
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
- failed to stat proxy plugin config %q: %w
- %s: cannot stat %q: %w
- %s: cannot resolve symlink %q: %w
- %s: cannot stat resolved path %q: %w
- %s: resolved path %q is still a symlink
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/0d3390248099f41f.
Report an issue: GitHub.