golangci/golangci-lint · error

unable to open file %s: %w

Error message

unable to open file %s: %w

What it means

When a formatter runs as an analyzer pass, golangci-lint reads the target file from disk before passing it to the formatter. If os.ReadFile fails, the filename and cause are wrapped in this error and the pass fails. This means the file listed in the diagnostics/positions no longer exists or is unreadable.

Source

Thrown at pkg/goformatters/analyzer.go:31

	"github.com/golangci/golangci-lint/v2/pkg/goformatters/internal"
	"github.com/golangci/golangci-lint/v2/pkg/logutils"
)

// NewAnalyzer converts a [Formatter] to an [analysis.Analyzer].
func NewAnalyzer(logger logutils.Log, doc string, formatter Formatter) *analysis.Analyzer {
	return &analysis.Analyzer{
		Name: formatter.Name(),
		Doc:  doc,
		Run: func(pass *analysis.Pass) (any, error) {
			for _, file := range pass.Files {
				position, isGoFile := goanalysis.GetGoFilePosition(pass, file)
				if !isGoFile {
					continue
				}

				input, err := os.ReadFile(position.Filename)
				if err != nil {
					return nil, fmt.Errorf("unable to open file %s: %w", position.Filename, err)
				}

				output, err := formatter.Format(position.Filename, input)
				if err != nil {
					return nil, fmt.Errorf("error while running %s: %w", formatter.Name(), err)
				}

				if !bytes.Equal(input, output) {
					newName := filepath.ToSlash(position.Filename)
					oldName := newName + ".orig"

					patch := diff.Diff(oldName, input, newName, output)

					err = internal.ExtractDiagnosticFromPatch(pass, file, patch, logger)
					if err != nil {
						return nil, fmt.Errorf("can't extract issues from %s diff output %q: %w", formatter.Name(), patch, err)
					}
				}

View on GitHub (pinned to ed7a235d2d)

Solutions

  1. Regenerate/restore the missing file, or re-run `go generate ./...`
  2. Check file permissions and ownership (chmod/chown)
  3. Re-run the linter from a clean checkout (git status; discard stale artifacts)
  4. Ensure no concurrent process deletes/renames files during the lint

Example fix

// shell: restore deleted generated file before linting
// before: golangci-lint fmt (file missing)
// after
go generate ./... && golangci-lint fmt
Defensive patterns

Strategy: validation

Validate before calling

// check file readability before running formatters
if _, err := os.Stat(path); err != nil {
    log.Fatalf("file missing/unreadable: %v", err)
}

Try / catch

// in the analyzer: wrap and skip gracefully
if _, err := os.ReadFile(path); err != nil {
    return fmt.Errorf("unable to open file %s: %w", path, err)
}

Prevention

When it happens

Trigger: position.Filename points to a file that was deleted, renamed, or is unreadable (permissions) at the time the formatter analyzer runs.

Common situations: Generated files removed between listing and formatting; files deleted by a prior run without --fix cleanup; permission issues (running as different user, root-owned files); files on unmounted volumes.

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 golangci/golangci-lint@ed7a235d2d (2026-09-02). Data as JSON: /api/errors/c9c6fb841f890f9f. Report an issue: GitHub.