Skip to content

Commit 2ec30b0

Browse files
pkg/goanalysis: expose underlying errors
If compilation or building of a Go package fails, export data will not be available. Previously, we would mask the underlying failure and display only a message that "no export data" was available. This has led to lots of confusion among golangci-lint users (and users at my company, which is how I discovered this problem). #3996 #4630 #4912 #4964 #5037 #5051 #5184 #5428 #5437 In addition to numerous discussions. The only common thread between the responses to these discussions, is that the "no export data" error message is obscuring whatever the underlying problem is, and making it more difficult to troubleshoot. #2489 #2191 #2751 #3363 #4829 #4880 This fix simply walks the import tree and appends any found error messages to the "no export data" error message. This will make it much clearer for end users to discover the problem that is causing the linter to fail. Example output: ERRO Running error: can't run linter goanalysis_metalinter inspect: failed to load package errs: could not load export data: no export data for "github.com/segmentio/ctlstore/pkg/errs" because of error in imported package(s): error in package "github.com/segmentio/stats/v5": # github.com/segmentio/stats/v5 vendor/github.com/segmentio/stats/v5/tag.go:38:35: in call to slices.IsSortedFunc, type func(a Tag, b Tag) int of tagCompare does not match inferred type func(a Tag, b Tag) bool for func(a E, b E) bool Fixes #6056.
1 parent 374a8cf commit 2ec30b0

File tree

1 file changed

+26
-1
lines changed

1 file changed

+26
-1
lines changed

pkg/goanalysis/runner_loadingpackage.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,32 @@ func (lp *loadingPackage) loadFromExportData() error {
240240
}
241241
}
242242
if pkg.ExportFile == "" {
243-
return fmt.Errorf("no export data for %q", pkg.ID)
243+
seen := make(map[string]struct{})
244+
245+
count := 0
246+
var sb strings.Builder
247+
packages.Visit([]*packages.Package{pkg}, func(p *packages.Package) bool {
248+
if _, ok := seen[p.ID]; ok {
249+
return false
250+
}
251+
if count >= 3 {
252+
return false
253+
}
254+
seen[p.ID] = struct{}{}
255+
// Optionally skip test variants:
256+
if p.ForTest == "" && !strings.HasSuffix(p.PkgPath, ".test") {
257+
for _, e := range p.Errors {
258+
fmt.Fprintf(&sb, "error in package %q: %v\n", p.ID, e.Msg)
259+
count++
260+
}
261+
}
262+
return true // keep walking into p.Imports
263+
}, nil)
264+
err := fmt.Sprintf("no export data for %q", pkg.ID)
265+
if sb.Len() > 0 {
266+
err += fmt.Sprintf(" because of error in imported package(s): %v", sb.String())
267+
}
268+
return errors.New(err)
244269
}
245270
f, err := os.Open(pkg.ExportFile)
246271
if err != nil {

0 commit comments

Comments
 (0)