{"record":{"id":"52a2f34a916b95f8","repo":"Jguer/yay","slug":"s-callback-must-return-a-string-or-nil-got-s","errorCode":null,"errorMessage":"%s: callback must return a string or nil, got %s","messagePattern":"(.+?): callback must return a string or nil, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/settings/lua/autocmd.go","lineNumber":602,"sourceCode":"\tfor _, autocmd := range e.autocmds[eventName] {\n\t\tif err := e.L.CallByParam(glua.P{\n\t\t\tFn:      autocmd.callback,\n\t\t\tNRet:    1,\n\t\t\tProtect: true,\n\t\t}, newEventTable()); err != nil {\n\t\t\treturn \"\", false, fmt.Errorf(\"%s: %w\", eventName, wrapLuaErr(err))\n\t\t}\n\n\t\tvalue := e.L.Get(-1)\n\t\te.L.Pop(1)\n\n\t\tif value == glua.LNil {\n\t\t\tcontinue\n\t\t}\n\n\t\tstr, isStr := value.(glua.LString)\n\t\tif !isStr {\n\t\t\treturn \"\", false, fmt.Errorf(\"%s: callback must return a string or nil, got %s\", eventName, value.Type())\n\t\t}\n\n\t\trendered = string(str)\n\t\tok = true\n\t}\n\n\treturn rendered, ok, nil\n}\n\nfunc parseSearchFilterResult(value glua.LValue, valid map[SearchResultRef]int) ([]SearchResultRef, bool, error) {\n\tif value == glua.LNil {\n\t\treturn nil, false, nil\n\t}\n\n\ttbl, ok := value.(*glua.LTable)\n\tif !ok {\n\t\treturn nil, false, fmt.Errorf(\"callback must return nil or a table, got %s\", value.Type())\n\t}","sourceCodeStart":584,"sourceCodeEnd":620,"githubUrl":"https://github.com/Jguer/yay/blob/328f4b4939fb35f38c2f7c7ce3b8638a839bafa5/pkg/settings/lua/autocmd.go#L584-L620","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"-- before\nhandler = function(ev) return #ev.items end\n-- after\nhandler = function(ev) return tostring(#ev.items) end","handlingStrategy":"validation","validationCode":"-- Lua: enforce return contract at the end of the handler\nlocal function ret_string_or_nil(v)\n  if v == nil then return nil end\n  assert(type(v) == \"string\", \"handler must return string or nil\")\n  return v\nend","typeGuard":null,"tryCatchPattern":"out, ok, err := engine.FireEvent(eventName)\nif err != nil {\n    log.Printf(\"handler returned non-string: %v; using default render\", err)\n}","preventionTips":["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"],"tags":["lua","autocmd","callback","return-type","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"328f4b4939fb35f38c2f7c7ce3b8638a839bafa5","analyzedAt":"2026-09-07T16:45:12.608Z","contentChangedAt":"2026-09-07T16:45:12.608Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}