{"record":{"id":"0d8bd0d16a9037b5","repo":"Jguer/yay","slug":"expected-number-got-s","errorCode":null,"errorMessage":"expected number, got %s","messagePattern":"expected number, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/settings/lua/lua.go","lineNumber":177,"sourceCode":"\tswitch field.Kind() {\n\tcase reflect.String:\n\t\ts, ok := val.(lua.LString)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"expected string, got %s\", val.Type())\n\t\t}\n\n\t\tfield.SetString(string(s))\n\tcase reflect.Bool:\n\t\tb, ok := val.(lua.LBool)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"expected boolean, got %s\", val.Type())\n\t\t}\n\n\t\tfield.SetBool(bool(b))\n\tcase reflect.Int, reflect.Int64:\n\t\tn, ok := val.(lua.LNumber)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"expected number, got %s\", val.Type())\n\t\t}\n\n\t\tfield.SetInt(int64(n))\n\tcase reflect.Slice:\n\t\treturn assignStructSlice(field, val)\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported field kind %s\", field.Kind())\n\t}\n\n\treturn nil\n}\n\n// assignStructSlice fills a []Struct field from a Lua table keyed by name, e.g.\n//\n//\t{ [\"core\"] = { url = \"...\" }, [\"extra\"] = { url = \"...\" } }\n//\n// Each entry becomes one struct: the table key populates the element's\n// lua:\"name\" field and the sub-table populates the remaining fields. Entries","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/Jguer/yay/blob/328f4b4939fb35f38c2f7c7ce3b8638a839bafa5/pkg/settings/lua/lua.go#L159-L195","documentation":"assign maps a Lua value onto a reflect.Int/Int64 struct field and requires an LNumber. Lua has a single numeric type, but anything that is not a number (string, bool, table, nil) is rejected with an error naming the actual type. The caller wraps it with the yay.opt.<key> prefix.","triggerScenarios":"An init.lua option bound to an int field is set to a quoted string or other non-number, e.g. yay.opt.retries = \"3\" or yay.opt.timeout = nil.","commonSituations":"Quoting numbers out of habit from config formats where everything is a string; Lua arithmetic returning nil due to a missing variable; hex or formatted strings ('0x10', '5s').","solutions":["Remove quotes so the value is a Lua number: yay.opt.retries = 3","Convert deliberately with tonumber(...): yay.opt.retries = tonumber(os.getenv(\"RETRIES\"))","If the field actually needs a duration/string, change the Go field type and tag instead"],"exampleFix":"// before (init.lua)\nyay.opt.retries = \"3\"\n// after\nyay.opt.retries = 3","handlingStrategy":"validation","validationCode":"-- init.lua\nlocal n = tonumber(yay_opt_retries_raw)\nassert(n ~= nil, \"retries must be numeric\")\nyay.opt.retries = n","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"expected number\") {\n    fixNumberOptionInInitLua()\n}","preventionTips":["Write numeric options unquoted","Use tonumber() for values derived from env or strings","Keep durations as plain int fields (e.g. seconds)"],"tags":["lua","type-mismatch","configuration"],"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"}