Reproducer:

package main

import (
    "log"

    "golang.org/x/tools/go/packages"
)

func main() {
    pkgs, err := packages.Load(&packages.Config{
        Mode: packages.LoadSyntax,
    }, "module/pkg")
    if err != nil {
        log.Fatal(err)
    }
    packages.PrintErrors(pkgs)
}

module/pkg package contains a file, that has a syntax error.

package pkg

func a() {
    var a
}
$ go run .
-: # module/pkg
pkg/invalid.go:4:7: syntax error: unexpected newline, expected type
/home/mateusz/tmp/module/pkg/invalid.go:4:7: expected type, found newline
/home/mateusz/tmp/module/pkg/invalid.go:4:6: declared and not used: a

This happens in two cases, when NeedDeps is not specified or NeedExportFile is set. In such cases the -export=true is passed to go list. That in turn causes it to return an error, which ends up being stored in Package.Errors with Kind == ListError. go/packages additionally parses the files, that go list returned, and it append them to Package.Errors, thus we end up with duplicated errors.

CC @adonovan @findleyr @matloob

Comment From: mateusz834

This is what go/package executes:

$ GOROOT= GOPATH=/home/mateusz/go GO111MODULE= GOPROXY= PWD=/home/mateusz/tmp/module go list -e -json=Name,ImportPath,Error,Dir,GoFiles,IgnoredGoFiles,IgnoredOtherFiles,CFiles,CgoFiles,CXXFiles,MFiles,HFiles,FFiles,SFiles,SwigFiles,SwigCXXFiles,SysoFiles,CompiledGoFiles,Export,DepOnly,Imports,ImportMap,Module -compiled=true -test=false -export=true -deps=true -find=false -pgo=off -- module/pkg
{
        "Dir": "/home/mateusz/tmp/module/pkg",
        "ImportPath": "module/pkg",
        "Name": "pkg",
        "Module": {
                "Path": "module",
                "Main": true,
                "Dir": "/home/mateusz/tmp/module",
                "GoMod": "/home/mateusz/tmp/module/go.mod",
                "GoVersion": "1.24.2"
        },
        "GoFiles": [
                "invalid.go"
        ],
        "CompiledGoFiles": [
                "invalid.go"
        ],
        "Error": {
                "ImportStack": [],
                "Pos": "",
                "Err": "# module/pkg\npkg/invalid.go:4:7: syntax error: unexpected newline, expected type\n"
        }
}

Comment From: gabyhelp

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: mateusz834

I wonder whether the solution to this is just to clear errors from go list for packages that go/packages parses directly i.e. when ExportFile is not used to load the package. But then we could possibly hide some real error. I think that that such case could happen with go:embed, as this errors are only returned there (through go list). So it seems like go list should notify that this is a parse/type-check error?

Comment From: mateusz834

So it seems like go list should notify that this is a parse/type-check error?

We might also detect that case as:

err.Pos == "" && strings.HasPrefix(err.Msg, fmt.Sprintf("# %v\n", pkg.ImportPath))

Comment From: gopherbot

Change https://go.dev/cl/682855 mentions this issue: go/packages: remove duplicated syntax/type-check errors from go list