golangci/golangci-lint · error
open source file: %w
Error message
open source file: %w
What it means
copyBinary wraps the error from os.Open of the built binary inside the repo directory (filepath.Join(b.repo, binaryName), cleaned via filepath.Clean). The %w preserves the underlying *os.PathError (e.g. ENOENT, EACCES). It means the builder could not open the compiled artifact for reading before copying it to the destination.
Source
Thrown at pkg/commands/internal/builder.go:212
)
cmd.Dir = b.repo
output, err := cmd.CombinedOutput()
if err != nil {
b.log.Warnf("%s", string(output))
return fmt.Errorf("%s: %w", strings.Join(cmd.Args, " "), err)
}
return nil
}
func (b Builder) copyBinary(binaryName string) error {
src := filepath.Join(b.repo, binaryName)
source, err := os.Open(filepath.Clean(src))
if err != nil {
return fmt.Errorf("open source file: %w", err)
}
defer func() { _ = source.Close() }()
info, err := source.Stat()
if err != nil {
return fmt.Errorf("stat source file: %w", err)
}
if b.cfg.Destination != "" {
err = os.MkdirAll(b.cfg.Destination, os.ModePerm)
if err != nil {
return fmt.Errorf("create destination directory: %w", err)
}
}
dst, err := os.OpenFile(filepath.Join(b.cfg.Destination, binaryName), os.O_RDWR|os.O_CREATE|os.O_TRUNC, info.Mode())
if err != nil {View on GitHub (pinned to ed7a235d2d)
Solutions
- Verify the built binary exists at filepath.Join(b.repo, binaryName) — run ls on that exact path after the build step
- Confirm getBinaryName() returns the same filename go build was told to produce (-o flag), including any GOOS/GOARCH prefixes
- Check the b.repo configuration points at the directory containing the artifact
- Check file permissions on the binary (chmod +r) and that the user running the build can read it
- Inspect the wrapped *os.PathError in the message to distinguish not-found (ENOENT) from permission (EACCES)
Example fix
// before go build ./cmd/tool // after go build -o tool ./cmd/tool # ensure output name matches binaryName used by copyBinary
Defensive patterns
Strategy: validation
Validate before calling
src := filepath.Join(repo, binaryName)
if info, err := os.Stat(src); err != nil {
return fmt.Errorf("binary %s missing before copy: %w", src, err)
} else if info.IsDir() {
return fmt.Errorf("%s is a directory, expected a binary", src)
} Try / catch
if err := b.copyBinary(name); err != nil {
var perr *fs.PathError
if errors.As(err, &perr) && errors.Is(perr, fs.ErrNotExist) {
log.Fatalf("built binary not found at %s: rebuild with the correct -o output name", perr.Path)
}
return err
} Prevention
- Make go build emit exactly the filename getBinaryName() expects (explicit -o)
- After the build step, assert the artifact exists before copying
- Pin and verify b.repo points at the build output directory
- In CI, archive the artifact immediately to avoid later-stage cleanup races
When it happens
Trigger: Builder.Build ran go build successfully (or skipped it) but os.Open(b.repo/<binaryName>) failed: the binary was not produced at the expected path, binaryName from getBinaryName() does not match the actual output file, the file was deleted between build and copy, or the process lacks read permission.
Common situations: go build output name differs from getBinaryName() (e.g. GOOS/GOARCH suffix added by -o or goreleaser-style naming), building in a dirty CI checkout where the artifact is elsewhere, repo path misconfigured so src points at a nonexistent directory, or read permissions stripped on the artifact.
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
- stat source file: %w
- create destination file: %w
- copy source to destination: %w
- file %s open: %w
- file %s not found: %w
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/5c45259f478a65ad.
Report an issue: GitHub.