golangci/golangci-lint · error

can't open file %s: %w

Error message

can't open file %s: %w

What it means

When computing line-length (lll) issues, golangci-lint reopens each source file from disk (os.Open on position.Filename). If the file can't be opened — missing, permission denied, or path issues — getLLLIssuesForFile wraps the OS error with this message and aborts the linter run.

Source

Thrown at pkg/golinters/lll/lll.go:60

		if err != nil {
			return err
		}
	}

	return nil
}

func getLLLIssuesForFile(pass *analysis.Pass, file *ast.File, maxLineLen int, tabSpaces string) error {
	position, isGoFile := goanalysis.GetGoFilePosition(pass, file)
	if !isGoFile {
		return nil
	}

	nonAdjPosition := pass.Fset.PositionFor(file.Pos(), false)

	f, err := os.Open(position.Filename)
	if err != nil {
		return fmt.Errorf("can't open file %s: %w", position.Filename, err)
	}

	defer f.Close()

	ft := pass.Fset.File(file.Pos())

	lineNumber := 0
	multiImportEnabled := false

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		lineNumber++

		line := scanner.Text()
		line = strings.ReplaceAll(line, "\t", tabSpaces)

		if strings.HasPrefix(line, goCommentDirectivePrefix) {
			continue

View on GitHub (pinned to ed7a235d2d)

Solutions

  1. Check the file exists and is readable: ls -l <file> and fix permissions (chmod/chown) or restore the file (git checkout -- <file>)
  2. Regenerate deleted generated files before running golangci-lint
  3. Run golangci-lint from the module root so relative paths resolve
  4. Check symlink targets exist; fix or remove broken symlinks

Example fix

# before
$ golangci-lint run
# can't open file /path/to/generated_gen.go: no such file or directory
# after
$ make generate   # regenerate the missing file
$ golangci-lint run
Defensive patterns

Strategy: try-catch

Validate before calling

import fs from 'node:fs'
for (const f of filesToLint) {
  try { fs.accessSync(f, fs.constants.R_OK) } catch (e) {
    throw new Error(`lll precondition failed: ${f} not readable (${e.message})`)
  }
}

Type guard

const isReadableFile = (p) => { try { return fs.statSync(p).isFile() && !!(fs.accessSync(p, fs.constants.R_OK) ?? true) } catch { return false } }

Try / catch

try {
  await runGolangciLint(['--enable=lll'])
} catch (e) {
  if (/can't open file .*: /.test(String(e))) {
    // recover file (git checkout / regenerate) and retry once
    await restoreMissingFiles(); await runGolangciLint(['--enable=lll'])
  } else { throw e }
}

Prevention

When it happens

Trigger: The file referenced by the AST position no longer exists or isn't readable at lint time: deleted/renamed between generation and lint, unreadable permissions, symlink to nonexistent target, running in a container without the file mounted.

Common situations: Generated code files removed before linting, read-only or root-owned checkout (permission denied), linting outside the module where relative paths break, cgo/generated files with unusual paths.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02). Data as JSON: /api/errors/dcc87bfa9a1db20f. Report an issue: GitHub.