Jguer/yay · error
: callback must return a string or nil, got
Error message
%s: callback must return a string or nil, got %s
What it means
After invoking an autocmd callback, the engine checks its single return value. Callbacks must return nil (skip) or an LString; any other Lua type (number, boolean, table, function) triggers this error naming the actual Lua type via value.Type(). This contract lets the hook control rendered output as a string.
Solutions
- Return nil when the callback has nothing to contribute.
- Coerce non-string values with tostring() before returning, e.g. return tostring(n).
- Remove a stray `return` of the event table or other objects from the callback.
- Confirm only one value is returned (extra values are ignored but the first must be string/nil).
Example fix
-- before handler = function(ev) return #ev.items end -- after handler = function(ev) return tostring(#ev.items) end
Defensive patterns
Strategy: validation
Validate before calling
-- Lua: enforce return contract at the end of the handler local function ret_string_or_nil(v) if v == nil then return nil end assert(type(v) == "string", "handler must return string or nil") return v end
Try / catch
out, ok, err := engine.FireEvent(eventName)
if err != nil {
log.Printf("handler returned non-string: %v; using default render", err)
} Prevention
- Explicitly return nil when there is nothing to contribute
- Use tostring() on any computed non-string value before returning
- Never return the event table or other objects from these callbacks
When it happens
Trigger: An autocmd callback returns a number (e.g. `return 42`), a boolean, or a table instead of a string or nil; the callback returns nothing but was written expecting a different protocol, or implicitly returns multiple/odd values.
Common situations: Users forget tostring() on computed numbers; they return the input event table by mistake; they come from other hook systems that accept any truthy value.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- %s %s: %w
- %s: %w
- callback must return nil or table, got
- callback must return nil or a table, got
- exclude must be a table
AI-assisted analysis of Jguer/yay@328f4b4939 (2026-09-07).
Data as JSON: /api/errors/52a2f34a916b95f8.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/settings/lua/autocmd.go:602
for _, autocmd := range e.autocmds[eventName] {
if err := e.L.CallByParam(glua.P{
Fn: autocmd.callback,
NRet: 1,
Protect: true,
}, newEventTable()); err != nil {
return "", false, fmt.Errorf("%s: %w", eventName, wrapLuaErr(err))
}
value := e.L.Get(-1)
e.L.Pop(1)
if value == glua.LNil {
continue
}
str, isStr := value.(glua.LString)
if !isStr {
return "", false, fmt.Errorf("%s: callback must return a string or nil, got %s", eventName, value.Type())
}
rendered = string(str)
ok = true
}
return rendered, ok, nil
}
func parseSearchFilterResult(value glua.LValue, valid map[SearchResultRef]int) ([]SearchResultRef, bool, error) {
if value == glua.LNil {
return nil, false, nil
}
tbl, ok := value.(*glua.LTable)
if !ok {
return nil, false, fmt.Errorf("callback must return nil or a table, got %s", value.Type())
}View on GitHub (pinned to 328f4b4939)