golang-migrate/migrate · error
x-no-tx-wrap: %s
Error message
x-no-tx-wrap: %s
What it means
The sqlcipher driver's Open parses the x-no-tx-wrap URL query parameter as a boolean (strconv.ParseBool) to decide whether each migration should run outside a transaction. If the value is present but not a valid boolean ("1", "t", "true", "0", "f", "false"), Open returns fmt.Errorf("x-no-tx-wrap: %s", err). The error message embeds the underlying parse error and the offending value.
Source
Thrown at database/sqlcipher/sqlcipher.go:112
}
dbfile := strings.Replace(migrate.FilterCustomQuery(purl).String(), "sqlite3://", "", 1)
db, err := sql.Open("sqlite3", dbfile)
if err != nil {
return nil, err
}
qv := purl.Query()
migrationsTable := qv.Get("x-migrations-table")
if len(migrationsTable) == 0 {
migrationsTable = DefaultMigrationsTable
}
noTxWrap := false
if v := qv.Get("x-no-tx-wrap"); v != "" {
noTxWrap, err = strconv.ParseBool(v)
if err != nil {
return nil, fmt.Errorf("x-no-tx-wrap: %s", err)
}
}
mx, err := WithInstance(db, &Config{
DatabaseName: purl.Path,
MigrationsTable: migrationsTable,
NoTxWrap: noTxWrap,
})
if err != nil {
return nil, err
}
return mx, nil
}
func (m *Sqlite) Close() error {
return m.db.Close()
}
View on GitHub (pinned to 01a9643f14)
Solutions
- Change the query parameter value to a strconv.ParseBool-accepted string: 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
- Remove the x-no-tx-wrap parameter entirely if you want the default (transaction-wrapped) behavior.
- Trim whitespace and shell quotes from the connection string before passing it to migrate.Open/sql.Open.
Example fix
// before dsn := "sqlcipher://data/app.db?x-no-tx-wrap=yes" // parse error // after dsn := "sqlcipher://data/app.db?x-no-tx-wrap=true"
Defensive patterns
Strategy: validation
Validate before calling
if v := q.Get("x-no-tx-wrap"); v != "" {
if _, err := strconv.ParseBool(v); err != nil {
return fmt.Errorf("invalid x-no-tx-wrap %q: use 1/t/true or 0/f/false", v)
}
} Type guard
func validBoolParam(v string) bool {
_, err := strconv.ParseBool(v)
return err == nil
} Try / catch
d, err := sqlcipher.Open(dsn)
if err != nil {
if strings.HasPrefix(err.Error(), "x-no-tx-wrap:") {
return fmt.Errorf("fix DSN boolean param (allowed: 1,t,true,0,f,false): %w", err)
}
return err
} Prevention
- Only use Go-parseable booleans (1/t/true/0/f/false) in x-no-tx-wrap.
- Validate the DSN with url.ParseQuery before passing to Open.
- Trim whitespace/quotes from DSNs sourced from env vars or templates.
- Omit the parameter entirely when the default (tx-wrapped) behavior is wanted.
When it happens
Trigger: Opening with a URL like sqlcipher://db.sqlite?x-no-tx-wrap=yes (or "on", "TRUE ", any value strconv.ParseBool rejects) — the parameter is present and non-empty but not a Go-recognized bool string.
Common situations: Users writing human-style booleans ("yes", "on", "y") in the DSN; copy-pasting flags from other tools that accept different boolean syntax; trailing whitespace or shell quoting artifacts in the connection string from env vars.
Related errors
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/b801b05e94cad879.
Report an issue: GitHub.