{"record":{"id":"972c32416a78ba39","repo":"golangci/golangci-lint","slug":"parallel-golangci-lint-is-running","errorCode":null,"errorMessage":"parallel golangci-lint is running","messagePattern":"parallel golangci-lint is running","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/run.go","lineNumber":217,"sourceCode":"\tsw := timeutils.NewStopwatch(\"pkgcache\", c.log.Child(logutils.DebugKeyStopwatch))\n\n\tpkgCache, err := cache.NewCache(sw, c.log.Child(logutils.DebugKeyPkgCache))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build packages cache: %w\", err)\n\t}\n\n\tguard := load.NewGuard()\n\n\tpkgLoader := lint.NewPackageLoader(c.log.Child(logutils.DebugKeyLoader), c.cfg, args, c.goenv, guard)\n\n\tc.contextBuilder = lint.NewContextBuilder(c.cfg, pkgLoader, pkgCache, guard)\n\n\tif err = initHashSalt(c.log.Child(logutils.DebugKeyGoModSalt), c.buildInfo.Version, c.cfg); err != nil {\n\t\treturn fmt.Errorf(\"failed to init hash salt: %w\", err)\n\t}\n\n\tif ok := c.acquireFileLock(); !ok {\n\t\treturn errors.New(\"parallel golangci-lint is running\")\n\t}\n\n\treturn nil\n}\n\nfunc (c *runCommand) postRun(_ *cobra.Command, _ []string) {\n\tc.releaseFileLock()\n}\n\nfunc (c *runCommand) execute(_ *cobra.Command, _ []string) {\n\tneedTrackResources := logutils.IsVerbose() || c.opts.PrintResourcesUsage\n\n\ttrackResourcesEndCh := make(chan struct{})\n\n\t// Note: this defer must be before ctx.cancel defer\n\tdefer func() {\n\t\t// wait until resource tracking finished to print properly\n\t\tif needTrackResources {","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/golangci/golangci-lint/blob/ed7a235d2d771152056fdc142a9855567c5796a9/pkg/commands/run.go#L199-L235","documentation":"`runCommand.preRunE` (pkg/commands/run.go:217) acquires an exclusive file lock before running the linter. If another golangci-lint process already holds the lock (`c.acquireFileLock()` returns false), the new process aborts with this error. It prevents concurrent golangci-lint runs from clobbering the shared cache, which can corrupt analysis results. The lock is released by `postRun` when the previous run finishes.","triggerScenarios":"Launching a second `golangci-lint run` in the same project while a previous instance is still executing; an editor plugin/IDE (e.g. gopls integration or language server) auto-running the linter in the background at the same time as a manual/CI run.","commonSituations":"Parallel CI jobs or make targets linting the same checkout concurrently; an IDE's on-save lint colliding with a terminal run; a previous golangci-lint run crashed leaving lock state that has not yet been cleaned up; running the linter on the same directory from two shells.","solutions":["Wait for the currently running golangci-lint process to finish, then re-run the command","Find and stop the concurrent instance (editor plugin, watch mode, or parallel CI job) before linting","Serialize linting in CI/scripts (e.g. a lock or `flock`) or configure the editor to not auto-run golangci-lint","If a stale process is truly gone, remove leftover lock state from the cache directory and retry"],"exampleFix":"# before (Makefile)\ncheck: lint test\nlint:\n\tgolangci-lint run &\n\tgo test ./...\n# after\ncheck: lint test\nlint:\n\tgolangci-lint run\n\tgo test ./...","handlingStrategy":"retry","validationCode":"// wait for an in-flight run to release the lock before re-running\nfor attempts := 0; attempts < 30; attempts++ {\n\tif err := exec.Command(\"golangci-lint\", \"run\").Run(); err == nil {\n\t\tbreak\n\t} else if !strings.Contains(err.Error(), \"parallel golangci-lint is running\") {\n\t\tbreak\n\t}\n\ttime.Sleep(2 * time.Second)\n}","typeGuard":null,"tryCatchPattern":"out, err := cmd.CombinedOutput()\nif err != nil && strings.Contains(string(out), \"parallel golangci-lint is running\") {\n\ttime.Sleep(5 * time.Second) // then retry once\n}","preventionTips":["Do not run golangci-lint concurrently on the same project directory","Disable duplicate linting (IDE auto-lint + manual/CI run at once)","Serialize lint steps in CI when multiple jobs share one checkout","Clean up stale lock/cache state after a killed golangci-lint process"],"tags":["golangci-lint","file-lock","concurrency"],"backgroundTag":"concurrent-run-lock-conflict","analyzedSha":"ed7a235d2d771152056fdc142a9855567c5796a9","analyzedAt":"2026-09-02T18:47:33.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}