gastownhall/beads · error
unterminated string starting at position %d
Error message
unterminated string starting at position %d
What it means
A quoted string was opened with " or ' but the input ended (rune 0) before the matching closing quote. readString (internal/query/lexer.go:201) reports the position where the string started, not where EOF was hit.
Source
Thrown at internal/query/lexer.go:201
if unicode.IsDigit(r) || r == '-' || r == '+' {
l.backup()
return l.readNumberOrDuration(startPos)
}
if isIdentStart(r) {
l.backup()
return l.readIdent(startPos)
}
return Token{}, fmt.Errorf("unexpected character %q at position %d", r, startPos)
}
}
// readString reads a quoted string.
func (l *Lexer) readString(quote rune, startPos int) (Token, error) {
var sb strings.Builder
for {
r := l.next()
if r == 0 {
return Token{}, fmt.Errorf("unterminated string starting at position %d", startPos)
}
if r == quote {
return Token{Type: TokenString, Value: sb.String(), Pos: startPos}, nil
}
if r == '\\' {
// Handle escape sequences
escaped := l.next()
switch escaped {
case 'n':
sb.WriteRune('\n')
case 't':
sb.WriteRune('\t')
case '\\':
sb.WriteRune('\\')
case '"':
sb.WriteRune('"')
case '\'':
sb.WriteRune('\'')View on GitHub (pinned to 71377f2769)
Solutions
- Add the matching closing quote at the end of the string value.
- If the value itself contains the same quote character, escape it with a backslash: `title="say \"hi\""`.
- Check shell quoting: a single-quoted shell string can swallow the query's quotes; wrap the whole query in double quotes at the shell level.
- Verify the query text programmatically: count unescaped " and ' characters before calling Parse.
Example fix
// before
query.Parse("title=\"bug report")
// after
query.Parse("title=\"bug report\"") Defensive patterns
Strategy: validation
Validate before calling
func balancedQuotes(q string) bool {
var q1, q2 bool
for i := 0; i < len(q); i++ {
switch q[i] {
case '\\':
i++
case '\'':
q1 = !q1
case '"':
q2 = !q2
}
}
return !q1 && !q2
} Try / catch
if _, err := query.Parse(q); err != nil {
var pos int
if _, scan := fmt.Sscanf(err.Error(), "unterminated string starting at position %d", &pos); scan == nil {
return fmt.Errorf("missing closing quote for string at byte %d", pos)
}
return err
} Prevention
- Always close quotes on the same line; the lexer has no multi-line strings
- Escape embedded quotes with backslash (\" or \')
- When passing through a shell, wrap the whole query in double quotes so inner quotes survive
- Run balancedQuotes() on generated queries before Parse
When it happens
Trigger: query.Parse with an unbalanced quote: `title="bug report`, `status='open`, or a quote opened and a newline/EOF reached because the closing quote was deleted during editing.
Common situations: Truncated shell commands (closing quote on the same line got eaten by shell quoting rules); hand-edited saved queries; copying text where the trailing quote was lost; embedding values containing quotes without escaping (e.g. `title="say \"hi\""` miscounted).
Related errors
- unexpected character '!' at position %d (did you mean '!=' o
- unexpected character %q at position %d
- unterminated escape sequence at position %d
- expected digit at position %d
- closed does not support %s operator
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/08833019b7f11a1c.
Report an issue: GitHub.