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

  1. Return nil when the callback has nothing to contribute.
  2. Coerce non-string values with tostring() before returning, e.g. return tostring(n).
  3. Remove a stray `return` of the event table or other objects from the callback.
  4. 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

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


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)