{"record":{"id":"2a0e813b2e9e1df2","repo":"Jguer/yay","slug":"each-result-must-be-a-table","errorCode":null,"errorMessage":"each result must be a table","messagePattern":"each result must be a table","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/settings/lua/autocmd.go","lineNumber":636,"sourceCode":"\tif !ok {\n\t\treturn nil, false, fmt.Errorf(\"callback must return nil or a table, got %s\", value.Type())\n\t}\n\n\tvar (\n\t\trefs     []SearchResultRef\n\t\tparseErr error\n\t)\n\n\tseen := mapset.NewThreadUnsafeSet[SearchResultRef]()\n\n\ttbl.ForEach(func(_ glua.LValue, val glua.LValue) {\n\t\tif parseErr != nil {\n\t\t\treturn\n\t\t}\n\n\t\tentry, ok := val.(*glua.LTable)\n\t\tif !ok {\n\t\t\tparseErr = fmt.Errorf(\"each result must be a table\")\n\t\t\treturn\n\t\t}\n\n\t\tsource, ok := entry.RawGetString(\"source\").(glua.LString)\n\t\tif !ok {\n\t\t\tparseErr = fmt.Errorf(\"result source must be a string\")\n\t\t\treturn\n\t\t}\n\n\t\tname, ok := entry.RawGetString(\"name\").(glua.LString)\n\t\tif !ok {\n\t\t\tparseErr = fmt.Errorf(\"result name must be a string\")\n\t\t\treturn\n\t\t}\n\n\t\tref := SearchResultRef{Source: string(source), Name: string(name)}\n\t\tif _, exists := valid[ref]; !exists {\n\t\t\tparseErr = fmt.Errorf(\"unknown search result %s/%s\", ref.Source, ref.Name)","sourceCodeStart":618,"sourceCodeEnd":654,"githubUrl":"https://github.com/Jguer/yay/blob/328f4b4939fb35f38c2f7c7ce3b8638a839bafa5/pkg/settings/lua/autocmd.go#L618-L654","documentation":"While iterating the table returned by a search-filter callback, each element must itself be a table describing one result. When an element is a non-table value (string, number, etc.), the ForEach loop records this error into parseErr, which the caller then wraps with the event name (error 51).","triggerScenarios":"The callback returns an array of strings/numbers such as {'bufferlines', 'symbols'} instead of an array of tables with source/name keys.","commonSituations":"Users model results as a flat list of names because other filter APIs accept plain string lists; they pass through the active table's keys instead of building result entries.","solutions":["Wrap each returned item in a table: { source = \"...\", name = \"...\" }.","Only include entries for results you want to keep, drawn from the active result set.","Check the error wrapping to confirm it is the element-type failure rather than the source/name field failures."],"exampleFix":"-- before\nreturn { \"bufferlines\", \"symbols\" }\n-- after\nreturn { { source = \"bufferlines\", name = \"bufferlines\" }, { source = \"symbols\", name = \"symbols\" } }","handlingStrategy":"type-guard","validationCode":"-- Lua: filter out non-table entries before returning\nlocal entries = {}\nfor _, e in ipairs(raw) do\n  if type(e) == \"table\" then entries[#entries+1] = e end\nend\nreturn entries","typeGuard":"function is_result_entry(v) return type(v) == \"table\" and type(v.source) == \"string\" and type(v.name) == \"string\" end","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"each result must be a table\") {\n    log.Print(\"filter returned non-table entries; check return shape\")\n}","preventionTips":["Return an array of tables, never an array of strings or numbers","Build entries with a small constructor helper so the shape is always correct","Validate the return value with a type-guard loop before returning"],"tags":["lua","search-filter","schema","validation"],"backgroundTag":"unexpected-response-shape","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"}