What I checked first
Searched LazyVim issues and discussions for credo, hadolint, linters_by_ft, fish linter. The only related hit is #3808, and its fix (#3809) is what introduced this. Reproduced on a clean lazy.minit install of LazyVim 99970099 (2026-09-08), which is current main for this file.
Neovim version (nvim -v)
NVIM v0.12.5 (Release, LuaJIT 2.1.1788856981)
Operating system/version
macOS 26.6.2 (25G83)
Describe the bug
The lang.elixir extra's nvim-lint spec assigns new tables instead of merging into the ones it receives:
opts = function(_, opts)
opts.linters_by_ft = {
elixir = { "credo" },
}
opts.linters = {
credo = { ... },
}
end,
So every linters_by_ft entry merged before this spec is silently thrown away. In practice that's core's fish = { "fish" }, lang.cmake's cmakelint and lang.docker's hadolint, plus any opts.linters override from an earlier spec. There's no warning, the linters just never run. Extras imported after elixir (go, haskell, kotlin) and user specs survive, which is why it's easy to miss: you only see it by looking at the resolved table.
Steps To Reproduce
- Save the repro below as
repro.lua, run nvim -u repro.lua, let it install, quit.
nvim -u repro.lua
:lua require("lazy").load({ plugins = { "nvim-lint" } }) print(vim.inspect(vim.tbl_keys(require("lint").linters_by_ft)))
Result: { "elixir" }
Changing only which extras are imported, and in what order:
| extras imported, in order |
linters_by_ft keys |
| docker |
dockerfile, fish |
| docker, elixir |
elixir |
| elixir, docker |
dockerfile, elixir |
| cmake, docker, elixir |
elixir |
The first, third and fourth rows came from a minimal LazyVim that reuses an installed plugin tree (mason disabled); the "docker, elixir" row reproduces with both that setup and the clean repro.lua below.
Expected Behavior
dockerfile, elixir and fish all present, whatever order the extras are imported in.
A table-form opts would let lazy merge it like the other extras do, e.g.
opts = {
linters_by_ft = {
elixir = { "credo" },
},
linters = {
credo = {
condition = function(ctx)
return vim.fs.find({ ".credo.exs" }, { path = ctx.filename, upward = true })[1]
end,
},
},
},
Repro
vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()
require("lazy.minit").repro({
spec = {
{ "LazyVim/LazyVim", import = "lazyvim.plugins" },
{ import = "lazyvim.plugins.extras.lang.docker" },
{ import = "lazyvim.plugins.extras.lang.elixir" },
},
})
What I checked first
Searched LazyVim issues and discussions for
credo,hadolint,linters_by_ft,fish linter. The only related hit is #3808, and its fix (#3809) is what introduced this. Reproduced on a cleanlazy.minitinstall of LazyVim99970099(2026-09-08), which is currentmainfor this file.Neovim version (nvim -v)
NVIM v0.12.5 (Release, LuaJIT 2.1.1788856981)
Operating system/version
macOS 26.6.2 (25G83)
Describe the bug
The
lang.elixirextra's nvim-lint spec assigns new tables instead of merging into the ones it receives:So every
linters_by_ftentry merged before this spec is silently thrown away. In practice that's core'sfish = { "fish" },lang.cmake'scmakelintandlang.docker'shadolint, plus anyopts.lintersoverride from an earlier spec. There's no warning, the linters just never run. Extras imported after elixir (go, haskell, kotlin) and user specs survive, which is why it's easy to miss: you only see it by looking at the resolved table.Steps To Reproduce
repro.lua, runnvim -u repro.lua, let it install, quit.nvim -u repro.lua:lua require("lazy").load({ plugins = { "nvim-lint" } }) print(vim.inspect(vim.tbl_keys(require("lint").linters_by_ft)))Result:
{ "elixir" }Changing only which extras are imported, and in what order:
linters_by_ftkeysdockerfile,fishelixirdockerfile,elixirelixirThe first, third and fourth rows came from a minimal LazyVim that reuses an installed plugin tree (mason disabled); the "docker, elixir" row reproduces with both that setup and the clean
repro.luabelow.Expected Behavior
dockerfile,elixirandfishall present, whatever order the extras are imported in.A table-form
optswould let lazy merge it like the other extras do, e.g.Repro