From within Neovim, I can execute the command :lua print(vim.fn.non_existent_function), and would get something like function: 0x01052bc2a8 as the printed output. But of course, if I were to actually call this function like :lua vim.fn.non_existent_function(), I'd get the following error message:

E5108: Error executing lua Vim:E117: Unknown function: non_existent_function
stack traceback:
        [C]: in function 'non_existent_function'
        [string ":lua"]:1: in main chunk

My guess is Neovim probably implemented this in a manner such that any member of the vim.fn table is automatically deemed to be a function, and its actual existence or lack thereof is only truly known when it is being called and passed onto its Vim counterpart. But please correct me if this is incorrect or inaccurate.

My main question is, why was it chosen to be like this? Does it not make more sense for non-existent keys to be nil in their corresponding value?

I discovered this when trying to check for the existence of a Vim/Neovim built-in function. But because vim.fn.non_existent_function is not nil, which is what I originally expected, that approach was not viable.

1 Answer 1


This is a part of internal implementation:


-- vim.fn.{func}(...)
vim.fn = setmetatable({}, {
  __index = function(t, key)
    local _fn
    if vim.api[key] ~= nil then
      _fn = function()
        error(string.format('Tried to call API function with vim.fn: use vim.api.%s instead', key))
      _fn = function(...)
        return vim.call(key, ...)
    t[key] = _fn
    return _fn

As you can see there is no check for function existence here. Everything is delayed until actual vim.call

why was it chosen to be like this?

The question feels a bit incorrect, as we are not a part of the devteam. If you really wonder you should better browse through project's github issues and discussions. Or to contact the developers directly. However, at the very least, one should realize that all user-defined (not for builtins) VimScript functions may be created and disposed at runtime freely. So any check performed by the Lua wrapper may get outdated easily.

Anyway, all API functions should present under vim.api standard table, while checking for existence of a VimScript function in runtime should be done by calling :h exists() VimScript function. This is a normal way to go.

  • Thank you for the informative answer.
    – Jethro Cao
    Oct 15, 2023 at 17:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.