golang-migrate/migrate · error
unable to parse option x-multi-statement: %w
Error message
unable to parse option x-multi-statement: %w
What it means
The `x-multi-statement` pgx DSN option enables multi-statement migration files (with `x-multi-statement-max-size` bounding the batch size). This error is wrapped from strconv.ParseBool when the option's value cannot be parsed as a Go boolean, and Open aborts before connecting to the database.
Source
Thrown at database/pgx/pgx.go:215
}
}
multiStatementMaxSize := DefaultMultiStatementMaxSize
if s := purl.Query().Get("x-multi-statement-max-size"); len(s) > 0 {
multiStatementMaxSize, err = strconv.Atoi(s)
if err != nil {
return nil, err
}
if multiStatementMaxSize <= 0 {
multiStatementMaxSize = DefaultMultiStatementMaxSize
}
}
multiStatementEnabled := false
if s := purl.Query().Get("x-multi-statement"); len(s) > 0 {
multiStatementEnabled, err = strconv.ParseBool(s)
if err != nil {
return nil, fmt.Errorf("unable to parse option x-multi-statement: %w", err)
}
}
lockStrategy := purl.Query().Get("x-lock-strategy")
lockTable := purl.Query().Get("x-lock-table")
px, err := WithInstance(db, &Config{
DatabaseName: purl.Path,
MigrationsTable: migrationsTable,
MigrationsTableQuoted: migrationsTableQuoted,
StatementTimeout: time.Duration(statementTimeout) * time.Millisecond,
MultiStatementEnabled: multiStatementEnabled,
MultiStatementMaxSize: multiStatementMaxSize,
LockStrategy: lockStrategy,
LockTable: lockTable,
})
if err != nil {View on GitHub (pinned to 01a9643f14)
Solutions
- Set the value to a strconv.ParseBool-accepted string: true/false, 1/0, t/f, T/F, TRUE/FALSE, True/False.
- Remove the parameter if multi-statement support is not needed (defaults to false).
- Log the final DSN after config substitution and confirm the parameter is intact (no spaces, correct URL encoding).
- Normalize application-level booleans (yes/no/on/off) to Go booleans before composing the migrate URL.
Example fix
// before dsn := "postgres://user:pass@host/db?x-multi-statement=enable" // after dsn := "postgres://user:pass@host/db?x-multi-statement=true"
Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(dsn)
if err != nil { return err }
if v := u.Query().Get("x-multi-statement"); v != "" {
if _, err := strconv.ParseBool(v); err != nil {
return fmt.Errorf("x-multi-statement must be a Go boolean, got %q", v)
}
} Type guard
func isValidGoBool(s string) bool { _, err := strconv.ParseBool(s); return err == nil } Try / catch
drv, err := pgx.Open(dsn)
if err != nil && strings.Contains(err.Error(), "unable to parse option x-multi-statement") {
return fmt.Errorf("x-multi-statement accepts only true/false/1/0/t/f: %w", err)
} Prevention
- Never substitute on/off or yes/no booleans into Go-style DSN options
- Construct DSN query params with url.Values{}.Encode() to avoid formatting drift
- Test DSN composition with env vars unset to catch empty substitutions
When it happens
Trigger: Calling pgx.Open with a DSN containing `x-multi-statement=<invalid>`, e.g. `x-multi-statement=enable`, `x-multi-statement=1 ` with a trailing space, `x-multi-statement=yes`, or a value mangled by URL encoding/templating.
Common situations: Enabling multi-statement migrations for MySQL-style SQL files against Postgres and typing non-Go boolean values; env-var substitution inserting an empty or malformed value; copying examples from other tools that accept on/off or yes/no.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- unable to parse option x-migrations-table-quoted: %w
- x-migrations-table must be quoted (for instance '"migrate"."
- "%s" MigrationsTable contains too many dot characters
- unknown lock strategy "%s"
- no database name
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/c381150b1f86cba7.
Report an issue: GitHub.