gastownhall/beads · error
unterminated escape sequence at position %d
Error message
unterminated escape sequence at position %d
What it means
Inside a quoted string, a backslash started an escape sequence but the input ended immediately after the backslash (the escaped rune was 0). readString (internal/query/lexer.go:221) reports position l.pos-1, which is the position of the trailing backslash.
Source
Thrown at internal/query/lexer.go:221
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('\'')
case 0:
return Token{}, fmt.Errorf("unterminated escape sequence at position %d", l.pos-1)
default:
sb.WriteRune(escaped)
}
} else {
sb.WriteRune(r)
}
}
}
// readNumberOrDuration reads a number or duration (e.g., 7d, 24h).
//
// Unsigned digit-led tokens that continue into identifier characters
// (e.g. "1-alpha", "42day-sla", "9.3.1") are re-lexed as identifiers so
// they can stand in unquoted on the value side of comparisons like
// "label=1-alpha". Signed forms ("-3-foo") still error — the user has
// to quote them.
func (l *Lexer) readNumberOrDuration(startPos int) (Token, error) {
var sb strings.BuilderView on GitHub (pinned to 71377f2769)
Solutions
- Close the string properly: a trailing backslash before EOF is always wrong; end with the closing quote.
- Escape literal backslashes by doubling them: `path="C:\\\\Users"`.
- If the backslash was meant literally as the final character, write `\\` then the quote: `value="end\\\\"`.
- Check shell escaping — an extra shell-level `\\` can consume the query's closing quote, leaving the lexer's backslash dangling at EOF.
Example fix
// before
query.Parse("title=\"report\\") // backslash then EOF
// after
query.Parse("title=\"report\\\\\"") // escaped backslash + closing quote Defensive patterns
Strategy: validation
Validate before calling
// Reject a string value whose final character before EOF is a dangling backslash
func trailingBackslash(q string) bool {
return strings.HasSuffix(q, "\\") || strings.HasSuffix(q, "\\'") && !strings.HasSuffix(q, "\\\\'")
} Try / catch
if _, err := query.Parse(q); err != nil && strings.Contains(err.Error(), "unterminated escape sequence") {
return fmt.Errorf("query ends with a bare backslash; escape it as \\\\")
} Prevention
- Double every literal backslash: \\ for one backslash
- Never end a quoted value with a single backslash
- Beware double-escaping when the query passes through a shell plus a config file
- Normalize Windows paths (forward slashes) before embedding in queries
When it happens
Trigger: query.Parse where the string's last character before EOF is a backslash: `title="path\\` (value ends with `\\` at EOF) or `status='open\\`.
Common situations: Windows-style path values cut off (`C:\\Users\\...` truncated); a value ending in a backslash where the author forgot the lexer requires escaping (`\\` for a literal backslash) and the closing quote was also lost; template-generated queries where a trailing backslash fell out of variable interpolation.
Related errors
- unexpected character '!' at position %d (did you mean '!=' o
- unexpected character %q at position %d
- unterminated string starting 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/a97d821b162d1fea.
Report an issue: GitHub.