larksuite/cli · critical
binary not executable: %w
Error message
binary not executable: %w
What it means
VerifyBinary runs the newly downloaded binary with `--version` under a context timeout and wraps any exec failure as "binary not executable". The library throws this because a self-update must prove the replacement binary actually runs before swapping it in; if exec.CommandContext cannot start or complete the process, the download is rejected as unsafe to install. The wrapped cause distinguishes ENOENT, permission, format, and timeout-style failures.
Source
Thrown at internal/selfupdate/updater.go:452
// Prefer PATH resolution so npm global bin symlinks pick up the newly
// installed binary (#836). If `lark-cli` is not on PATH (e.g. the user
// invoked this process by absolute path), fall back to the running
// executable — same as the pre-#836 secondary resolution path.
exe, err := execLookPath("lark-cli")
if err != nil {
exe, err = vfs.Executable()
if err != nil {
return fmt.Errorf("cannot locate binary: %w", err)
}
}
ctx, cancel := context.WithTimeout(context.Background(), verifyTimeout)
defer cancel()
out, err := exec.CommandContext(ctx, exe, "--version").Output()
if ctx.Err() == context.DeadlineExceeded {
return fmt.Errorf("binary verification timed out after %s", verifyTimeout)
}
if err != nil {
return fmt.Errorf("binary not executable: %w", err)
}
fields := strings.Fields(strings.TrimSpace(string(out)))
if len(fields) == 0 {
return fmt.Errorf("empty version output")
}
actual := strings.TrimPrefix(fields[len(fields)-1], "v")
expected := strings.TrimPrefix(expectedVersion, "v")
if actual != expected {
return fmt.Errorf("expected version %s, got %q", expectedVersion, actual)
}
return nil
}
// Truncate returns the last maxLen runes of s.
func Truncate(s string, maxLen int) string {
if maxLen <= 0 {
return ""
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Re-download the release and verify its checksum; the file is likely truncated or corrupt
- chmod +x the downloaded binary before invoking the updater (or fix the packaging step that sets permissions)
- Confirm the artifact matches GOOS/GOARCH of the host
- Run the downloaded binary manually with --version to see the raw exec error
- Check whether antivirus/EDR is quarantining newly written executables
Example fix
// before (downloaded but not executable)
bin downloaded, exec fails: "binary not executable: fork/exec /tmp/...: permission denied"
// after
if err := os.Chmod(binPath, 0o755); err != nil { return err }
// then proceed with update.VerifyBinary(...) Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(binPath)
if err != nil || info.Mode().Perm()&0o111 == 0 {
return fmt.Errorf("downloaded binary is not executable: %s", binPath)
}
// sanity-run it before update
if out, err := exec.Command(binPath, "--version").Output(); err != nil {
return fmt.Errorf("pre-check failed: %w", err)
} else { _ = out } Try / catch
if err := update.VerifyBinary(ctx, path, expectedVersion); err != nil {
var execErr *exec.ExitError
if errors.As(err, &execErr) { log.Printf("verify exit error: %v", execErr.Stderr) }
return fmt.Errorf("update aborted, keeping current binary: %w", err)
} Prevention
- Verify download checksums against release manifests
- Set the executable bit atomically in the download/temp-file path
- Smoke-test binaries in CI on the exact GOOS/GOARCH matrix
- Keep antivirus exclusions for the updater's temp directory
When it happens
Trigger: exec.CommandContext(ctx, exe, "--version").Output() returns a non-nil error: the downloaded file is not executable (missing +x), is corrupt/truncated, is built for the wrong OS/arch, a dynamic linker is missing, or the process fails/exits non-zero during verification.
Common situations: Failed or partial download left a truncated file; update artifact published for the wrong platform; a CI pipeline stripped the executable bit; antivirus quarantined the freshly written binary; the binary crashes on startup in the target environment.
Related errors
- cannot locate binary: %w
- binary verification timed out after %s
- exec provider command is empty
- exec provider security audit failed: %w
- L2: field %q has format: binary but type = %q (want string)
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/0043573afa967ebe.
Report an issue: GitHub.