{"record":{"id":"c9c6fb841f890f9f","repo":"golangci/golangci-lint","slug":"unable-to-open-file-s-w","errorCode":null,"errorMessage":"unable to open file %s: %w","messagePattern":"unable to open file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/goformatters/analyzer.go","lineNumber":31,"sourceCode":"\t\"github.com/golangci/golangci-lint/v2/pkg/goformatters/internal\"\n\t\"github.com/golangci/golangci-lint/v2/pkg/logutils\"\n)\n\n// NewAnalyzer converts a [Formatter] to an [analysis.Analyzer].\nfunc NewAnalyzer(logger logutils.Log, doc string, formatter Formatter) *analysis.Analyzer {\n\treturn &analysis.Analyzer{\n\t\tName: formatter.Name(),\n\t\tDoc:  doc,\n\t\tRun: func(pass *analysis.Pass) (any, error) {\n\t\t\tfor _, file := range pass.Files {\n\t\t\t\tposition, isGoFile := goanalysis.GetGoFilePosition(pass, file)\n\t\t\t\tif !isGoFile {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tinput, err := os.ReadFile(position.Filename)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"unable to open file %s: %w\", position.Filename, err)\n\t\t\t\t}\n\n\t\t\t\toutput, err := formatter.Format(position.Filename, input)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"error while running %s: %w\", formatter.Name(), err)\n\t\t\t\t}\n\n\t\t\t\tif !bytes.Equal(input, output) {\n\t\t\t\t\tnewName := filepath.ToSlash(position.Filename)\n\t\t\t\t\toldName := newName + \".orig\"\n\n\t\t\t\t\tpatch := diff.Diff(oldName, input, newName, output)\n\n\t\t\t\t\terr = internal.ExtractDiagnosticFromPatch(pass, file, patch, logger)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"can't extract issues from %s diff output %q: %w\", formatter.Name(), patch, err)\n\t\t\t\t\t}\n\t\t\t\t}","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/golangci/golangci-lint/blob/ed7a235d2d771152056fdc142a9855567c5796a9/pkg/goformatters/analyzer.go#L13-L49","documentation":"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.","triggerScenarios":"position.Filename points to a file that was deleted, renamed, or is unreadable (permissions) at the time the formatter analyzer runs.","commonSituations":"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.","solutions":["Regenerate/restore the missing file, or re-run `go generate ./...`","Check file permissions and ownership (chmod/chown)","Re-run the linter from a clean checkout (git status; discard stale artifacts)","Ensure no concurrent process deletes/renames files during the lint"],"exampleFix":"// shell: restore deleted generated file before linting\n// before: golangci-lint fmt (file missing)\n// after\ngo generate ./... && golangci-lint fmt","handlingStrategy":"validation","validationCode":"// check file readability before running formatters\nif _, err := os.Stat(path); err != nil {\n    log.Fatalf(\"file missing/unreadable: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"// in the analyzer: wrap and skip gracefully\nif _, err := os.ReadFile(path); err != nil {\n    return fmt.Errorf(\"unable to open file %s: %w\", path, err)\n}","preventionTips":["Regenerate files before linting (go generate)","Never delete/move files concurrently with lint","Fix permissions on generated artifacts"],"tags":["golangci-lint","formatters","file-io"],"backgroundTag":"file-not-found","analyzedSha":"ed7a235d2d771152056fdc142a9855567c5796a9","analyzedAt":"2026-09-02T18:47:33.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}