You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
SQLite: non-ASCII character (em-dash) in SQL comment corrupts generated queries #4372
When a SQL comment between two named queries contains an em-dash (—, U+2014), sqlc corrupts the generated Go code. The trailing ? parameter placeholder is stripped from the query, and the comment text leaks into the Go source as a misplaced comment.
In our production codebase this caused ~15 queries to silently fail at runtime. The corruption went unnoticed because the Go code compiles — sqlc generates the correct number of params in the struct/function, but the SQL string is truncated.
Expected generated output
const updateItem = `-- name: UpdateItem :exec
UPDATE items SET name = ? WHERE id = ?
`
func (q *Queries) UpdateItem(ctx context.Context, arg UpdateItemParams) error {
_, err := q.db.ExecContext(ctx, updateItem, arg.Name, arg.ID)
return err
}
Actual generated output
const updateItem = `-- name: UpdateItem :exec
UPDATE items SET name = ? WHERE id =
`
// section — divider
func (q *Queries) UpdateItem(ctx context.Context, arg UpdateItemParams) error {
_, err := q.db.ExecContext(ctx, updateItem, arg.Name, arg.ID)
return err
}
Note:
WHERE id = is missing the trailing ? — runtime SQL syntax error
The comment // section — divider leaked into the Go code
Two args are passed to ExecContext but the SQL only has one ? placeholder
The bug cascades: in a file with many queries after the offending comment, every query loses its last ? and gets ?; prepended from the previous query.
Replacing the em-dash (—) with a regular hyphen (-) fixes the issue.
Relevant log output
const updateItem = `-- name: UpdateItem :execUPDATE items SET name = ? WHERE id =`
// section — divider
func (q *Queries) UpdateItem(ctx context.Context, arg UpdateItemParams) error {
_, err := q.db.ExecContext(ctx, updateItem, arg.Name, arg.ID)
return err
}
Database schema
CREATETABLEitems (id INTEGERPRIMARY KEY, name TEXTNOT NULL);
SQL queries
-- name: GetItem :oneSELECT id, name FROM items WHERE id = ?;
-- section — divider-- name: UpdateItem :execUPDATE items SET name = ? WHERE id = ?;
Still reproducible on v1.31.1 (the current latest release), sqlite engine, Linux — so the fix appears to have regressed or covered a narrower case.
Minimal A/B repro (only the comment differs):
-- name: DelA :execrows-- Retention sweep (batched) — same shape as X. <-- em-dash (U+2014)DELETEFROM t WHERE id IN (
SELECTsub.idFROM t AS sub WHEREsub.x< ? LIMIT ?
)
Generated const on v1.31.1 (note the missing closing paren):
constdelA=`-- name: DelA :execrowsDELETE FROM t WHERE id IN ( SELECT sub.id FROM t AS sub WHERE sub.x < ? LIMIT ?`
Replacing the em-dash with an ASCII - regenerates the statement correctly.
Two field observations that may help pinpoint the offset math:
The corruption is position-dependent: the same set of multi-byte characters may generate fine for months until an unrelated edit elsewhere in the file shifts byte offsets onto the rune (we had a query file where this exploded only after a different query above it grew by a few bytes).
It corrupts the tail of the reconstructed statement — in our worst case a WHERE id = lost its trailing ? entirely, and another query's ORDER BY a, b DESC, te. was cut mid-identifier. The generated code compiles fine; the statement only fails at runtime with SQL logic error: incomplete input.
Our workaround (works, but shouldn't be necessary): keep queries/*.sql pure ASCII and guard it in CI.
Activity
fix(sqlite): convert ANTLR character indices to byte offsets for sour…
kyleconroy commentedon Apr 17, 2026
Closing as a duplicate of #4372
exploded commentedon Apr 20, 2026
@kyleconroy Kyle - can you clarify which one this is a duplicate of? This is issue #4372
exploded commentedon May 7, 2026
Looks like this is the same bug as #4235 ? Should be fixed by PR #4373.
endtoend: pin sqlite query text with multi-byte UTF-8 comments (#4568)
mickeyzzc commentedon Sep 2, 2026
Still reproducible on v1.31.1 (the current latest release), sqlite engine, Linux — so the fix appears to have regressed or covered a narrower case.
Minimal A/B repro (only the comment differs):
Generated const on v1.31.1 (note the missing closing paren):
Replacing the em-dash with an ASCII
-regenerates the statement correctly.Two field observations that may help pinpoint the offset math:
WHERE id =lost its trailing?entirely, and another query'sORDER BY a, b DESC, te.was cut mid-identifier. The generated code compiles fine; the statement only fails at runtime withSQL logic error: incomplete input.Our workaround (works, but shouldn't be necessary): keep
queries/*.sqlpure ASCII and guard it in CI.kyleconroy commentedon Sep 2, 2026
The fix has not been released yet, it's only been merged to
main