{"record":{"id":"699e9776abd9d7b9","repo":"gastownhall/beads","slug":"type-mismatch-for-formula-vardef-expected-string","errorCode":null,"errorMessage":"type mismatch for formula.VarDef: expected string or table but found %T","messagePattern":"type mismatch for formula\\.VarDef: expected string or table but found %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/types.go","lineNumber":190,"sourceCode":"\t\tif req, ok := val[\"required\"].(bool); ok {\n\t\t\tv.Required = req\n\t\t}\n\t\tif enum, ok := val[\"enum\"].([]interface{}); ok {\n\t\t\tfor _, e := range enum {\n\t\t\t\tif s, ok := e.(string); ok {\n\t\t\t\t\tv.Enum = append(v.Enum, s)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif pattern, ok := val[\"pattern\"].(string); ok {\n\t\t\tv.Pattern = pattern\n\t\t}\n\t\tif typ, ok := val[\"type\"].(string); ok {\n\t\t\tv.Type = typ\n\t\t}\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"type mismatch for formula.VarDef: expected string or table but found %T\", data)\n\t}\n}\n\n// Step defines a work item to create when the formula is instantiated.\ntype Step struct {\n\t// ID is the unique identifier within this formula.\n\t// Used for dependency references and bond points.\n\tID string `json:\"id\"`\n\n\t// Title is the issue title (supports {{variable}} substitution).\n\tTitle string `json:\"title\"`\n\n\t// Description is the issue description (supports substitution).\n\tDescription string `json:\"description,omitempty\"`\n\n\t// Notes are additional notes for the issue (supports substitution).\n\tNotes string `json:\"notes,omitempty\"`\n","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/types.go#L172-L208","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\n[[variables]]\nport = 8080\n// after\n[[variables]]\nname = \"port\"\ntype = \"int\"\ndefault = 8080","handlingStrategy":"validation","validationCode":"for i, v := range rawVars {\n    switch v.(type) {\n    case string, map[string]any:\n    default:\n        return fmt.Errorf(\"variables[%d] must be a string or table, got %T\", i, v)\n    }\n}","typeGuard":"func isValidVarDef(data any) bool {\n    switch data.(type) {\n    case string, map[string]any:\n        return true\n    default:\n        return false\n    }\n}","tryCatchPattern":"if err := tomlDecode(f, &formula); err != nil {\n    if strings.Contains(err.Error(), \"type mismatch for formula.VarDef\") { /* point user at the variables section */ }\n    return err\n}","preventionTips":["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."],"tags":["toml","unmarshal","formula-vars"],"backgroundTag":"toml-type-mismatch","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}