{"record":{"id":"0ab4d54806d06ede","repo":"gastownhall/beads","slug":"unexpected-character-q-in-expression","errorCode":null,"errorMessage":"unexpected character %q in expression","messagePattern":"unexpected character %q in expression","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/range.go","lineNumber":191,"sourceCode":"\t\t\t\t\t}\n\t\t\t\t\ttokens = append(tokens, token{tokNumber, val})\n\t\t\t\t\ti = j\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\ttokens = append(tokens, token{tokMinus, 0})\n\t\tcase '*':\n\t\t\ttokens = append(tokens, token{tokMul, 0})\n\t\tcase '/':\n\t\t\ttokens = append(tokens, token{tokDiv, 0})\n\t\tcase '^':\n\t\t\ttokens = append(tokens, token{tokPow, 0})\n\t\tcase '(':\n\t\t\ttokens = append(tokens, token{tokLParen, 0})\n\t\tcase ')':\n\t\t\ttokens = append(tokens, token{tokRParen, 0})\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unexpected character %q in expression\", ch)\n\t\t}\n\t\ti++\n\t}\n\n\ttokens = append(tokens, token{tokEOF, 0})\n\treturn tokens, nil\n}\n\n// Parser state\ntype exprParser struct {\n\ttokens []token\n\tpos    int\n}\n\nfunc (p *exprParser) current() token {\n\tif p.pos >= len(p.tokens) {\n\t\treturn token{tokEOF, 0}\n\t}","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/range.go#L173-L209","documentation":"After handling digits, operators, parentheses, and range/variable syntax, tokenize() reaches the default branch for any character it does not recognize and rejects the whole expression. This is the catch-all lexical error for illegal characters in range expressions.","triggerScenarios":"EvaluateExpr or ValidateRange with an expression containing a character outside the supported token set — e.g. 'range 1..10 &' or '1..10 %3' or a stray comma/letter where an operand is expected.","commonSituations":"Shell metacharacters leaking into config, typos ('1..10!' instead of '1..10'), unsupported operators like '%' or '&', or locale/whitespace oddities like non-ASCII digits.","solutions":["Remove or replace the offending character reported by %q","Use only supported tokens: digits, '.', '+', '-', '*', '/', '^', '(', ')', and recognized variable syntax","Run ValidateRange first to fail fast with the same message"],"exampleFix":"// before\nrange 1..10 & 3 { ... }\n// after\nrange 1..10 { ... }","handlingStrategy":"validation","validationCode":"allowed := regexp.MustCompile(`^[0-9+\\-*/^().\\s{}]*$`)\nif !allowed.MatchString(expr) {\n    // reject before calling EvaluateExpr/ValidateRange\n}","typeGuard":null,"tryCatchPattern":"tokens, err := tokenize(expr)\nif err != nil && strings.Contains(err.Error(), \"unexpected character\") {\n    // strip or escape the offending character and retry once\n}","preventionTips":["Whitelist characters before passing user text into range expressions","Escape or reject shell/regex metacharacters at config boundaries","Add a ValidateRange call in every code path that accepts user-authored ranges"],"tags":["formula","tokenizer","syntax","parsing"],"backgroundTag":"unexpected-character-in-expression","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}