Skip to content

Crash in get_lsp_location_from_selection on Neovim v0.11+ due to missing offset_encoding #279

@artkpv

Description

@artkpv

Check if applicable

  • I have searched the existing issues (required)
  • I'm willing to help fix the problem and contribute a pull request

Describe the bug

Description
When using commands like ZkInsertLink (mapped to wil in some configs), the plugin crashes with the error:
Error executing Lua callback: vim/_editor.lua:0: s: expected string, got nil

Stack Trace

vim/_editor.lua: in function 'character_offset'
/usr/share/nvim/runtime/lua/vim/lsp/util.lua:2039: in function 'make_range_zk'
.../zk-nvim/lua/zk/util.lua:77: in function 'get_lsp_location_from_selection'
.../zk-nvim/lua/zk/commands/builtin.lua:83: in function 'insert_link'


**Cause**
Recent versions of Neovim (v0.10/v0.11+) strictly require the `offset_encoding` argument in `vim.lsp.util.make_given_range_params` to be a string.

In `lua/zk/util.lua`, the `get_offset_encoding` function has a logic error:

  elseif zk_client.offset_encoding == nil then
    vim.notify_once(...)
    -- MISSING: offset_encoding = "utf-16"
  else
    offset_encoding = zk_client.offset_encoding
  end
  return offset_encoding -- Returns nil!

When zk_client.offset_encoding is nil, the function returns nil, causing make_given_range_params to crash.

Suggested Fix
In lua/zk/util.lua:

elseif zk_client.offset_encoding == nil then
vim.notify_once(...)
offset_encoding = "utf-16" -- Add this line
else

How to reproduce?

For some buffers, when I press wil (insert a link)

zk configuration

❯ cat .zk/config.toml| grep -o '^[^#].*'
[note]
language = "en"
default-title = "Untitled"
filename = "{{id}}-{{slug title}}"
extension = "md"
template = "default.md"
exclude = [
    # Glob patterns are relative to the notebook root.

    # Hidden files and directories
    ".*",
    "**/.*",
    # Exclude specific directories and their contents recursively
    "bin",
    "bin/**",
    "assets",
    "assets/**",
    "files",
    "**/files",
    "**/files/**",
    "time",
    "time/**",
    # Specific system/tool directories
    ".aider",
    ".aider/**",
    ".app",
    ".claude",
    ".git",
    ".stfolder",
    ".stversions",
    ".vim",
    ".zettel-notes",
    ".zk",

    # Cache directories if needed (though covered by .*)
    ".aider.tags.cache.v3",
    ".aider.tags.cache.v4",
]
id-charset = "alphanum"
id-length = 4
id-case = "lower"
[extra]
[group.diary]
paths = [
	"2025",
	"2026",
	"2027",
	"2028",
]
[group.diary.note]
filename = "{{format-date now '%Y-%m-%d'}}-{{slug title}}"
template = "journal.md"
[format.markdown]
link-format = "markdown"
link-encode-path = true
link-drop-extension = false
hashtags = false
colon-tags = true
multiword-tags = false
[tool]
editor = "vim"
pager = "bat"
fzf-preview = "bat -p --color always {-1}"
[lsp]
[lsp.diagnostics]
dead-link = "none"
[lsp.completion]
[filter]
[alias]

Neovim configuration

With the fix I applied:


  {
    'zk-org/zk-nvim',
    config = function()
      require('zk').setup {

        -- Can be "telescope", "fzf", "fzf_lua", "minipick", "snacks_picker",
        -- or select" (`vim.ui.select`).
        picker = 'telescope',

        lsp = {
          -- `config` is passed to `vim.lsp.start(config)`
          config = {
            name = 'zk',
            cmd = { 'zk', 'lsp' },
            filetypes = { 'markdown' },
            -- on_attach = ...
            -- etc, see `:h vim.lsp.start()`
          },

          -- automatically attach buffers in a zk notebook that match the given filetypes
          auto_attach = {
            enabled = true,
          },
        },
      }

      -- HOTFIX: Patch zk.util to avoid crash on recent Neovim versions
      -- Issue: "s: expected string, got nil" in make_given_range_params
      local util = require('zk.util')
      
      util.get_lsp_location_from_selection = function()
        local bufnr = vim.api.nvim_get_current_buf()
        local encoding = 'utf-16'
        local client = vim.lsp.get_clients({ bufnr = bufnr, name = 'zk' })[1]
        if client and client.offset_encoding then
          encoding = client.offset_encoding
        end

        local params = vim.lsp.util.make_given_range_params(nil, nil, bufnr, encoding)
        return {
          uri = params.textDocument.uri,
          range = params.range,
        }
      end

      util.get_lsp_location_from_caret = function()
        local bufnr = vim.api.nvim_get_current_buf()
        local uri = vim.uri_from_bufnr(bufnr)
        local row, col = unpack(vim.api.nvim_win_get_cursor(0))
        
        -- Manual construction of range to avoid make_range_zk overhead/issues
        -- Logic matches original fix_cursor_location: line - 1, char + 1
        return {
          uri = uri,
          range = {
            start = { line = row - 1, character = col + 1 },
            ['end'] = { line = row - 1, character = col + 1 },
          },
        }
      end
    end,
  },

Environment

❯ zk --version && echo "system: `uname -srmo`" && nvim --version

zk 0.15.2
system: Linux 6.18.2-arch2-1 x86_64 GNU/Linux
NVIM v0.11.5
Build type: RelWithDebInfo
LuaJIT 2.1.1765228720
Run "nvim -V1 -v" for more info

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions