Jguer/yay · error

keys must be strings, got

Error message

keys must be strings, got %s

What it means

Thrown by `assignStructFields` when a key inside a struct-mapped Lua table is not a Lua string. Struct fields are looked up by string key against `lua:"..."` tags, so numeric or other key types cannot be matched.

Solutions

  1. Replace numeric keys in the option table with the documented string field names.
  2. Check the Go struct's lua tags for the exact key names.
  3. If the option truly needs a list, it should be a slice-type option, not a struct option.

Example fix

-- before
aur = { [1] = true }
-- after
aur = { build = true }
Defensive patterns

Strategy: validation

Validate before calling

-- ensure all keys in the entry table are strings
for k, _ in pairs(entry) do
  assert(type(k) == "string", "keys must be strings, got " .. type(k))
end

Prevention

When it happens

Trigger: An entry table written as an array (`{ [1] = ..., [2] = ... }`) or with computed/integer keys inside a named-entry option; `k.(lua.LString)` assertion fails during `tbl.ForEach`.

Common situations: Users mixing list syntax with table syntax, e.g. `build = { "make", "install" }` where the option expects named fields, or Lua code building keys with integers.

Related errors


AI-assisted analysis of Jguer/yay@328f4b4939 (2026-09-07). Data as JSON: /api/errors/638e8b2fbd9e28cf. Report an issue: GitHub.

Appendix: source

Thrown at pkg/settings/lua/lua.go:289

	field.Set(out)

	return nil
}

// assignStructFields assigns the entries of tbl onto struct value sv, matching
// each key against the lua:"..." tags in index. Unknown keys are errors so
// typos in nested option tables fail fast, mirroring top-level opt handling.
func assignStructFields(sv reflect.Value, tbl *lua.LTable, index map[string]int) error {
	var firstErr error

	tbl.ForEach(func(k, entry lua.LValue) {
		if firstErr != nil {
			return
		}

		key, ok := k.(lua.LString)
		if !ok {
			firstErr = fmt.Errorf("keys must be strings, got %s", k.Type())
			return
		}

		fieldIdx, found := index[string(key)]
		if !found {
			firstErr = fmt.Errorf("unknown key %q", string(key))
			return
		}

		if err := assign(sv.Field(fieldIdx), entry); err != nil {
			firstErr = fmt.Errorf("%s: %w", string(key), err)
		}
	})

	return firstErr
}

View on GitHub (pinned to 328f4b4939)