gastownhall/beads · error
type mismatch for formula.VarDef: expected string or table b
Error message
type mismatch for formula.VarDef: expected string or table but found %T
What it means
VarDef.UnmarshalTOML accepts either a plain string (variable name/shorthand) or a table with fields like type/default. Any other TOML type (integer, array, bool, etc.) triggers this error, which mirrors burntsushi/toml's Unmarshaler convention of naming the target type in the message.
Source
Thrown at internal/formula/types.go:190
if req, ok := val["required"].(bool); ok {
v.Required = req
}
if enum, ok := val["enum"].([]interface{}); ok {
for _, e := range enum {
if s, ok := e.(string); ok {
v.Enum = append(v.Enum, s)
}
}
}
if pattern, ok := val["pattern"].(string); ok {
v.Pattern = pattern
}
if typ, ok := val["type"].(string); ok {
v.Type = typ
}
return nil
default:
return fmt.Errorf("type mismatch for formula.VarDef: expected string or table but found %T", data)
}
}
// Step defines a work item to create when the formula is instantiated.
type Step struct {
// ID is the unique identifier within this formula.
// Used for dependency references and bond points.
ID string `json:"id"`
// Title is the issue title (supports {{variable}} substitution).
Title string `json:"title"`
// Description is the issue description (supports substitution).
Description string `json:"description,omitempty"`
// Notes are additional notes for the issue (supports substitution).
Notes string `json:"notes,omitempty"`
View on GitHub (pinned to 71377f2769)
Solutions
- Open the TOML file and find the variables entry that is not a string or table.
- Quote string values: `variables = ["name"]` not `variables = [name]`.
- Use table form for full definitions: `[variables.myvar]` with `type`/`default` keys.
- Validate the formula TOML before loading (e.g. `bd formula validate` if available, or a TOML linter).
Example fix
// before [[variables]] port = 8080 // after [[variables]] name = "port" type = "int" default = 8080
Defensive patterns
Strategy: validation
Validate before calling
for i, v := range rawVars {
switch v.(type) {
case string, map[string]any:
default:
return fmt.Errorf("variables[%d] must be a string or table, got %T", i, v)
}
} Type guard
func isValidVarDef(data any) bool {
switch data.(type) {
case string, map[string]any:
return true
default:
return false
}
} Try / catch
if err := tomlDecode(f, &formula); err != nil {
if strings.Contains(err.Error(), "type mismatch for formula.VarDef") { /* point user at the variables section */ }
return err
} Prevention
- Quote all bare strings in TOML variables entries.
- Use the [variables.name] table form for typed definitions.
- Add a TOML schema linter (e.g. taplo) to CI for formula files.
When it happens
Trigger: UnmarshalTOML is invoked by the TOML decoder when a formula's variables section contains a value that is neither a string nor an inline table, e.g. `variables = [1, 2]` or a bare boolean.
Common situations: Hand-editing a formula TOML and writing a variable as a number or list instead of a string or `[variables.name]` table; forgetting quotes around a string value.
Related errors
- formula has no source path
- encoding TOML: %w
- parse %s: %w
- toml: %w
- failed to parse team labels response: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/699e9776abd9d7b9.
Report an issue: GitHub.