vitessio/vitess · error
stray %% at the end of pattern
Error message
stray %% at the end of pattern
What it means
The strftime-style pattern compiler in go/mysql/datetime rejects format strings that end with a bare '%' — the trailing '%' has no following conversion specifier byte, so the compiled program would be incomplete. Returned by compile (invoked via New and Format) when strings.IndexByte finds '%' at the last position of the pattern.
Source
Thrown at go/mysql/datetime/strftime.go:34
*/
package datetime
import (
"errors"
"fmt"
"strings"
)
func compile(ds map[byte]Spec, p string, exec func(Spec)) error {
for l := len(p); l > 0; l = len(p) {
i := strings.IndexByte(p, '%')
if i < 0 {
exec(&fmtVerbatim{s: p})
break
}
if i == l-1 {
return errors.New(`stray %% at the end of pattern`)
}
// we found a '%'. we need the next byte to decide what to do next
// we already know that i < l - 1
// everything up to the i is verbatim
if i > 0 {
exec(&fmtVerbatim{s: p[:i]})
p = p[i:]
}
if spec, ok := ds[p[1]]; ok {
if spec == nil {
return fmt.Errorf(`unsupported format specifier: %%%c`, p[1])
}
exec(spec)
} else {
exec(&fmtVerbatim{s: p[1:2]})
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Remove the trailing '%' or add the intended specifier after it (e.g. '%%' for a literal percent sign)
- Double literal percent signs ('%%') in the pattern, since % introduces a specifier
- Trim or sanitize user-supplied format templates before compiling
Example fix
// before
out, err := datetime.Format("%Y-%m-%d %", ts)
// after
out, err := datetime.Format("%Y-%m-%d %%", ts) Defensive patterns
Strategy: validation
Validate before calling
func validStrftimePattern(p string) bool { return p == "" || !strings.HasSuffix(p, "%") } Type guard
func safeFormatPattern(p string) (string, bool) {
if strings.HasSuffix(p, "%") { return strings.TrimSuffix(p, "%"), false }
return p, true
} Try / catch
out, err := datetime.Format(pattern, ts)
if err != nil && strings.Contains(err.Error(), "stray %") {
out, err = datetime.Format(strings.TrimRight(pattern, "%"), ts)
} Prevention
- Never end a format string with a bare '%' — use '%%' for a literal percent
- Escape user-supplied templates before compiling
- Add a unit test asserting your production format strings compile
When it happens
Trigger: Format(pattern, t) or New(pattern) with a pattern whose last character is '%', e.g. "%Y-%m-%d %".
Common situations: Format strings assembled by string concatenation where a literal percent got orphaned; translating a format from another language and forgetting '%' must be escaped by doubling; copy-pasted templates with trailing whitespace stripped.
Related errors
- unsupported format specifier: %%%c
- overflow
- too many .s
- missing value for 'rate'
- missing value for 'path'
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/f8827c047686ccb4.
Report an issue: GitHub.