Skip to content

goLint: linting with golangci-lint v2 fails #3732

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
logica0419 opened this issue Mar 24, 2025 · 34 comments
Closed

goLint: linting with golangci-lint v2 fails #3732

logica0419 opened this issue Mar 24, 2025 · 34 comments

Comments

@logica0419
Copy link
Contributor

What version of Go, VS Code & VS Code Go extension are you using?

Version Information
  • Run go version to get version of Go from the VS Code integrated terminal.
    • go version go1.24.1 linux/amd64
  • Run gopls -v version to get version of Gopls from the VS Code integrated terminal.
    • golang.org/x/tools/gopls v0.18.1
  • Run code -v or code-insiders -v to get version of VS Code or VS Code Insiders.
    • 1.98.2
  • Check your installed extensions to get the version of the VS Code Go extension
    • 0.46.1
  • Run Ctrl+Shift+P (Cmd+Shift+P on Mac OS) > Go: Locate Configured Go Tools command.
# Tools Configuration


## Environment

GOBIN: undefined
toolsGopath: 
gopath: /home/logica/go
GOROOT: /usr/local/go
PATH: /home/logica/.vscode-server/bin/ddc367ed5c8936efe395cffeec279b04ffd7db78/bin/remote-cli:/home/linuxbrew/.linuxbrew/opt/clang-format/bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/mnt/c/Program Files/Common Files/Oracle/Java/javapath:/mnt/c/Program Files (x86)/Common Files/Intel/Shared Libraries/redist/intel64/compiler:/mnt/c/WINDOWS/System32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files/MATLAB/R2022a/bin:/mnt/c/Program Files (x86)/dotnet/:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files (x86)/Tailscale IPN/:/mnt/c/Program Files/Tailscale/:/mnt/c/Program Files (x86)/GnuPG/bin:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA app/NvDLISR:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Users/Takuto/AppData/Local/Microsoft/WindowsApps:/mnt/c/Program Files/Java/jdk-11.0.12/bin:/mnt/c/Users/Takuto/AppData/Local/Programs/Microsoft VS Code/bin:/snap/bin:/usr/local/go/bin:/home/logica/go/bin:/home/logica/.bun/bin:/home/logica/.krew/bin

## Tools

	go:	/usr/local/go/bin/go: go version go1.24.1 linux/amd64

	gopls:	/home/logica/go/bin/gopls	(version: v0.18.1 built with go: go1.24.1)
	gotests:	/home/logica/go/bin/gotests	(version: v1.6.0 built with go: go1.24.1)
	gomodifytags:	/home/logica/go/bin/gomodifytags	(version: v1.17.0 built with go: go1.24.1)
	impl:	/home/logica/go/bin/impl	(version: v1.4.0 built with go: go1.24.1)
	goplay:	/home/logica/go/bin/goplay	(version: v1.0.0 built with go: go1.24.1)
	dlv:	/home/logica/go/bin/dlv	(version: v1.24.1 built with go: go1.24.1)
	golangci-lint:	/home/logica/go/bin/golangci-lint	(version: v2.0.0 built with go: go1.24.1)
	golangci-lint:	/home/logica/go/bin/golangci-lint	(version: v2.0.0 built with go: go1.24.1)

## Go env

Workspace Folder (vault-provisioner): /home/logica/prj/personal/vault-provisioner

	AR='ar'
	CC='gcc'
	CGO_CFLAGS='-O2 -g'
	CGO_CPPFLAGS=''
	CGO_CXXFLAGS='-O2 -g'
	CGO_ENABLED='1'
	CGO_FFLAGS='-O2 -g'
	CGO_LDFLAGS='-O2 -g'
	CXX='g++'
	GCCGO='gccgo'
	GO111MODULE=''
	GOAMD64='v1'
	GOARCH='amd64'
	GOAUTH='netrc'
	GOBIN=''
	GOCACHE='/home/logica/.cache/go-build'
	GOCACHEPROG=''
	GODEBUG=''
	GOENV='/home/logica/.config/go/env'
	GOEXE=''
	GOEXPERIMENT=''
	GOFIPS140='off'
	GOFLAGS=''
	GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2113586740=/tmp/go-build -gno-record-gcc-switches'
	GOHOSTARCH='amd64'
	GOHOSTOS='linux'
	GOINSECURE=''
	GOMOD='/home/logica/prj/personal/vault-provisioner/go.mod'
	GOMODCACHE='/home/logica/go/pkg/mod'
	GONOPROXY=''
	GONOSUMDB=''
	GOOS='linux'
	GOPATH='/home/logica/go'
	GOPRIVATE=''
	GOPROXY='https://proxy.golang.org,direct'
	GOROOT='/usr/local/go'
	GOSUMDB='sum.golang.org'
	GOTELEMETRY='on'
	GOTELEMETRYDIR='/home/logica/.config/go/telemetry'
	GOTMPDIR=''
	GOTOOLCHAIN='auto'
	GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
	GOVCS=''
	GOVERSION='go1.24.1'
	GOWORK=''
	PKG_CONFIG='pkg-config'

Share the Go related settings you have added/edited

{
  "go.toolsManagement.autoUpdate": true,
  "go.lintOnSave": "workspace",
  "go.lintTool": "golangci-lint",
}

Describe the bug

After updating golangci-lint to v2, lining using golanci-lint always fails with the logs below.

2025-03-25 02:19:36.239 [info] Running checks...
2025-03-25 02:19:36.239 [info] Starting linting the current workspace at /home/logica/prj/personal/vault-provisioner
2025-03-25 02:19:36.407 [error] Error while running tool: /home/logica/go/bin/golangci-lint run --print-issued-lines=false --out-format=colored-line-number --issues-exit-code=0 ./...
2025-03-25 02:19:36.407 [error] Error: unknown flag: --print-issued-lines
Failed executing command with error: unknown flag: --print-issued-lines

This error occurs because --print-issued-lines and --out-format flags were deleted in v2.
These flags seem to have the same output in v2.

/home/logica/go/bin/golangci-lint run --output.text.print-issued-lines=false --output.text.path=stdout --output.text.colors=true --show-stats=false --issues-exit-code=0 ./...

Thus, we need to switch flags depending on the version of golangci-lint.

Steps to reproduce the behavior:

  1. Install golangci-lint v2
  2. Set "go.lintTool" to "golangci-lint"
  3. Run "Go: Lint Workspace" command

Screenshots or recordings

If applicable, add screenshots or recordings to help explain your problem.

@gopherbot gopherbot added this to the Untriaged milestone Mar 24, 2025
@logica0419
Copy link
Contributor Author

logica0419 commented Mar 24, 2025

I'm willing to work on this issue!
The current problem is detecting the version of golangci-lint inside goLint.ts.
Does someone have a good idea for that?

Declaring "golangci-lint v2" as a linter choice might be a good idea...

@firelizzard18
Copy link
Contributor

Declaring "golangci-lint v2" as a linter choice might be a good idea...

I think this is the best option. If it's feasible (I haven't looked at goLint.ts) I think it would be a good idea to detect "Error: unknown flag" and pop up a notification, "It appears that you are using golangci-lint v2, in which case you should set go.lintTool to golangci-lint-v2". @h9jiang?

@logica0419
Copy link
Contributor Author

That looks awesome to me! Thx

@gopherbot
Copy link
Collaborator

Change https://go.dev/cl/660415 mentions this issue: extension/src/goLint: adding golangci-lint-v2 to lintTool

@h9jiang
Copy link
Member

h9jiang commented Mar 25, 2025

Thank you for raising this issue and working on the CL.

Declaring "golangci-lint v2" as a linter choice might be a good idea...

This make sense.

There are some complexity here beyond the CL crafted. We need to figure out a way to make sure the different version of the binary can co-exist in the GOBIN. Both v1 and v2 golangci-lint have the exact same name, so calling go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest will overwrite the golangci-lint@v1 in the same GOBIN.

There is a FR raised in go asking for go install -o output See golang/go#44469. But not implemented yet.

@matloob suggested we can do the following to work this around:

  • Set GOBIN to a temp dir.
  • Install golangci-lint (v2) into the temp dir.
  • Rename the golangci-lint (v2) to golangci-lint-v2.
  • Move the golangci-lint-v2 from temp dir to GOBIN.

In the meantime, we need to consider another configuration go.toolsGopath: Location to install the Go tools that the extension depends on if you don't want them in your GOPATH..

As said above, there might be some extra work vscode-go need to do to manage different versions of the same binary like golangci-lint. If you think this is too much, I can work on this.

@h9jiang h9jiang modified the milestones: Untriaged, v0.48.0 Mar 25, 2025
@marcusthelin
Copy link

Is this being worked on?

@logica0419
Copy link
Contributor Author

logica0419 commented Mar 27, 2025

Is this being worked on?

Yup, of course!
Please check out the Gerrit change list from here.
#3732 (comment)

Sorry for making you wait.

@arhea
Copy link

arhea commented Mar 27, 2025

Submitted an implementation. Agree with all of @h9jiang points. Will likely need a more centralized way of supporting multiple versions of the same binary.

@logica0419
Copy link
Contributor Author

@arhea
I already working on this directly via Gerrit, so your PR would conflict with it.
I would appreciate it if you participate in the review process via Gerrit!
https://go.dev/cl/660415

Thank you,

@arhea
Copy link

arhea commented Mar 27, 2025

Great, will do!

@sherif-fanous
Copy link

If anyone is looking for a workaround until this feature is released this is what I did

  1. Make a copy of golangci-lint binary with a different name
cp ~/go/bin/golangci-lint ~/go/bin/golangci-lint-v2
  1. Update VSCode settings as follows
  "go.lintFlags": [
    "run",
    "--issues-exit-code=0",
    "--output.text.colors=true",
    "--output.text.path=stdout",
    "--output.text.print-issued-lines=false",
    "--show-stats=false"
  ],
  "go.lintTool": "golangci-lint-v2",

VSCode's settings validator will complain about the golangci-lint-v2 value not being valid but the extension will proceed to run the command ~/go/bin/golangci-lint-v2 run --issues-exit-code=0 --output.text.colors=true --output.text.path=stdout --output.text.print-issued-lines=false --show-stats=false and the extension will successfully display the linter's results in the editor and PROBLEMS tab

@h9jiang
Copy link
Member

h9jiang commented Mar 27, 2025

@sherif-fanous Thank you so much for the workaround provided.

One thing to note, cp ~/go/bin/golangci-lint ~/go/bin/golangci-lint-v2, ~/go/bin/golangci-lint will be v2. If the user ever switch back to golangci-lint, the linter will start failing because we will try to run v2's flag against v1's binary.

But the idea of keep the v2 binary as name golangci-lint-v2 is something we are planning to do.

We hope we can make this migration merged in v0.48.0 and we can release a prerelease version v0.47.2 to have this migration release early (if people are willing to switch to a prerelease version).

@marcusthelin
Copy link

The workaround mentioned above runs the linter command successfully, but when being reported in the editor, the path is duplicated.

Image

@sherif-fanous
Copy link

sherif-fanous commented Mar 28, 2025

@marcusthelin Not clear from the screenshot what you mean by the path is duplicated. I see 2 similar violations but on different lines (157 vs 159)

@marcusthelin
Copy link

@marcusthelin Not clear from the screenshot what you mean by the path is duplicated. I saw 2 similar violations but on different lines (157 vs 159)

Sorry. It should not be models/domain/models/domain. That path does not exist.

@dcarr45
Copy link

dcarr45 commented Mar 28, 2025

@marcusthelin had the same issue, looks like it was due to run.relative-path-mode: gomod in my .golangci.yml. Removing or setting to relative-path-mode: wd seems to make the paths resolve correctly.

Slightly confused because this issue persisted after I reverted to [email protected] - could've sworn I didn't have this problem before but might've borked my Go env somehow while swapping versions

@ldez
Copy link

ldez commented Mar 29, 2025

FYI, run.relative-path-mode has been introduced in v1.64 but with a default to wd (so invisible because it was the default).

Remember that:

  • golangci-lint v1 configuration is not compatible with golangci-lint v2.
  • golangci-lint v2 configuration is not compatible with golangci-lint v1.

You should migrate your configuration: https://golangci-lint.run/product/migration-guide/

@buzzdan
Copy link

buzzdan commented Apr 2, 2025

@ldez until this is fixed, maybe its worth considering changing the integration docs (as this is a potential blocker for migration)

@ldez
Copy link

ldez commented Apr 2, 2025

I will add the link to this issue inside the documentation.

@lummie
Copy link

lummie commented Apr 4, 2025

I'm willing to work on this issue! The current problem is detecting the version of golangci-lint inside goLint.ts. Does someone have a good idea for that?

Declaring "golangci-lint v2" as a linter choice might be a good idea...

I might be being to simplistic but can you not parse the output of golangci-lint version?

golangci-lint has version 2.0.2 built with go1.24.1 from 2b224c2c on 2025-03-25T21:36:18Z

@iainvm
Copy link

iainvm commented Apr 4, 2025

I'm willing to work on this issue! The current problem is detecting the version of golangci-lint inside goLint.ts. Does someone have a good idea for that?
Declaring "golangci-lint v2" as a linter choice might be a good idea...

I might be being to simplistic but can you not parse the output of golangci-lint version?

golangci-lint has version 2.0.2 built with go1.24.1 from 2b224c2c on 2025-03-25T21:36:18Z

This wouldn't work if you have many projects that use both v1 and v2.
As the extension would need to replace the binary back and forth needlessly. Rather than storing both and allowing the plugin to pick from both.

@logica0419
Copy link
Contributor Author

I'm willing to work on this issue! The current problem is detecting the version of golangci-lint inside goLint.ts. Does someone have a good idea for that?
Declaring "golangci-lint v2" as a linter choice might be a good idea...

I might be being to simplistic but can you not parse the output of golangci-lint version?

golangci-lint has version 2.0.2 built with go1.24.1 from 2b224c2c on 2025-03-25T21:36:18Z

@lummie
Hi! Thank you for the advice!
That idea also came to my mind, but I thought the approach was too non-reusable for this long-maintained extension.

But don't worry! I implemented the version detection logic differently in the current version of the Pull Request!

The detail: (https://go.dev/cl/660415)

  • New lintTool option added: golangci-lint-v2
  • By default, the versions of the tools you install from the command of the extension are
    • golangci-lint: The latest version of golangci-lint v1 (v1.64.8)
    • golangci-lint-v2: The latest version of golangci-lint v2
    • These two tools can be installed together in the same GOBIN.
  • The lintTool name will be the binary name, so when you install golangci-lint-v2 from the command, the binary name will be "golangci-lint-v2" accordingly.

Image

  • You can upgrade your golangci-lint binary to v2 manually.
  • When running lint, the binary and the flags to run are determined with the following logic:
    • lintTool = golangci-lint-2: Run "golangci-lint-v2" binary, appending v2 flags.
    • lintTool = golangci-lint: Run "golangci-lint" binary. Check the binary version with go version -m {golangci-lint path}
      • version = v1.x.x: Appending v1 flags.
      • version != v1.x.x: Appending v2 flags.

Image

If you have any further questions, please don't hesitate to mention me!

@holyspectral
Copy link

Just tried the fix. I had to add below settings to .golangci.yml in order to generate the path of findings correctly, but other than it it works great! Thanks!

run:                                                                                                   
  relative-path-mode: wd   

@ldez
Copy link

ldez commented Apr 8, 2025

If you have to set the relative path mode to wd, then this is a problem: the relative path mode is mainly for the paths used inside the configuration.
By using wd, you are losing the consistency of the v2 configuration paths.

@logica0419 I need a confirmation of the problem, and be sure that it is not a side effect of something inside the extension.
I can modify an option related to user-facing paths if needed.

@holyspectral
Copy link

holyspectral commented Apr 9, 2025

Without the relative-path-mode: wd line, the symptom varies depending on linters:

  • lll: no findings if the line is not added.
  • staticcheck: when I click the warning, it will show The editor could not be opened because the file was not found.. Upon further checking, the file path comes with a redundant prefix. For example, my file is supposed to be at internal/controller/xxx_controller.go, but the warning points to internal/controller/internal/controller/xxx_controller.go instead.

Here is my .golangci.yml. Hope it helps.

version: "2"
run:
  allow-parallel-runners: true
  relative-path-mode: wd
linters:
  default: none
  enable:
    - copyloopvar
    - dupl
    - errcheck
    - ginkgolinter
    - goconst
    - gocyclo
    - govet
    - ineffassign
    - lll
    - misspell
    - nakedret
    - prealloc
    - revive
    - staticcheck
    - unconvert
    - unparam
    - unused
  settings:
    revive:
      rules:
        - name: comment-spacings
  exclusions:
    generated: lax
    rules:
      - linters:
          - lll
        path: api/*
      - linters:
          - dupl
          - lll
        path: internal/*
    paths:
      - third_party$
      - builtin$
      - examples$
formatters:
  enable:
    - gofmt
    - goimports
  exclusions:
    generated: lax
    paths:
      - third_party$
      - builtin$
      - examples$

@ldez
Copy link

ldez commented Apr 9, 2025

I will take a look, thank you.

@iambocai
Copy link

iambocai commented Apr 9, 2025

For users seeking a temporary workaround:

https://youtrack.jetbrains.com/issue/GO-18363

@ldez
Copy link

ldez commented Apr 9, 2025

I tried the current master branch, and I confirm the problem.

I will add an option inside the next minor release of golangci-lint (v2.1): --path-mode=wd.

Edit: it doesn't require wd as path mode, the new option --path-mode=abs (v2.1) is enough and it's a more stable approach.

This option will only impact the output paths, but not the paths inside the configuration.

Note, path-mode != relative-path-mode:

  • run.relative-path-mode is used for the path matching inside the configuration
  • output.path-mode is only used for the report paths.

@logica0419 The extension will have to set up this option.

@logica0419
Copy link
Contributor Author

@holyspectral @ldez
I guess the relative-path-mode problem may not be related to the v2 update directly, so let's move on to the dirrent issue!
I'm going to bed soon, so I will create another issue to organize the info about the problem when I wake up.

@ldez
Copy link

ldez commented Apr 9, 2025

It's related to the update to v2:

  • v1: The report paths were relative to the wd
  • v2: The report paths are relative to the configuration file by default (or wd if no configuration file)

The current extension implementation will only work:

  • on files at the root level (if there is a configuration file)
  • or with relative-path-mode: wd (but the paths inside the configuration will not work)
  • or without a configuration file.

To illustrate the problem with relative-path-mode: wd, if we have the following configuration:

  exclusions:
    rules:
      - linters:
          - lll
        path: api/*

And if you edit a file inside api/, you will have reports from lll, but it should not.

But we can switch to another issue, no problem.

@logica0419
Copy link
Contributor Author

@ldez
Moving on to #3750

@h9jiang
Copy link
Member

h9jiang commented Apr 15, 2025

The v0.47.2 is now released with fix for this issue. See https://github.com/golang/vscode-go/releases/tag/v0.47.2

This is a prerelease version of vscode-go extension. You will need to manually switch to pre-release version of vscode-go.

Image

lvlcn-t added a commit to lvlcn-t/golangci-lint that referenced this issue Apr 26, 2025
This commit adds a note to the docs about how to integrate
golangci-lint v2 with VS Code since the Go extension's stable
version does not support it yet.

For more information on this, you can refer to the linked
[vscode-go#3732](golang/vscode-go#3732 (comment))
issue comment.

Signed-off-by: lvlcn-t <[email protected]>
lvlcn-t added a commit to lvlcn-t/golangci-lint that referenced this issue Apr 26, 2025
This commit adds a note to the docs about how to integrate
golangci-lint v2 with VS Code since the Go extension's stable
version does not support it yet.

For more information on this, you can refer to the linked
[vscode-go#3732](golang/vscode-go#3732 (comment))
issue comment.

Signed-off-by: lvlcn-t <[email protected]>
@adamk33n3r
Copy link

Even after upgrading to the pre-release version of the extension, I'm getting the same exact error message. I installed golangci-lint v2 via chocolatey.

@ldez
Copy link

ldez commented May 28, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.