golang-migrate/migrate · error
unable to parse option x-migrations-table-quoted: %w
Error message
unable to parse option x-migrations-table-quoted: %w
What it means
The pgx driver in golang-migrate accepts a boolean DSN query parameter `x-migrations-table-quoted` that controls whether the migrations table name is treated as a quoted (case-sensitive, possibly schema-qualified) SQL identifier. This error is wrapped from strconv.ParseBool when the value of that query parameter is not a valid boolean string ("1", "t", "true", "0", "f", "false"). The library throws it during Open to fail fast on an unparseable connection URL option.
Source
Thrown at database/pgx/pgx.go:184
return nil, err
}
// Driver is registered as pgx, but connection string must use postgres schema
// when making actual connection
// i.e. pgx://user:password@host:port/db => postgres://user:password@host:port/db
purl.Scheme = "postgres"
db, err := sql.Open("pgx/v4", migrate.FilterCustomQuery(purl).String())
if err != nil {
return nil, err
}
migrationsTable := purl.Query().Get("x-migrations-table")
migrationsTableQuoted := false
if s := purl.Query().Get("x-migrations-table-quoted"); len(s) > 0 {
migrationsTableQuoted, err = strconv.ParseBool(s)
if err != nil {
return nil, fmt.Errorf("unable to parse option x-migrations-table-quoted: %w", err)
}
}
if (len(migrationsTable) > 0) && (migrationsTableQuoted) && ((migrationsTable[0] != '"') || (migrationsTable[len(migrationsTable)-1] != '"')) {
return nil, fmt.Errorf("x-migrations-table must be quoted (for instance '\"migrate\".\"schema_migrations\"') when x-migrations-table-quoted is enabled, current value is: %s", migrationsTable)
}
statementTimeoutString := purl.Query().Get("x-statement-timeout")
statementTimeout := 0
if statementTimeoutString != "" {
statementTimeout, err = strconv.Atoi(statementTimeoutString)
if err != nil {
return nil, err
}
}
multiStatementMaxSize := DefaultMultiStatementMaxSize
if s := purl.Query().Get("x-multi-statement-max-size"); len(s) > 0 {
multiStatementMaxSize, err = strconv.Atoi(s)View on GitHub (pinned to 01a9643f14)
Solutions
- Change the x-migrations-table-quoted value to a Go-parseable boolean: 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
- Remove the x-migrations-table-quoted parameter entirely if you do not need a quoted migrations table identifier (it defaults to false).
- Print/log the DSN before passing to Open and verify no templating or environment substitution corrupted the value (watch for stray spaces or encoding).
- If your config layer produces non-Go booleans (e.g. yes/no), normalize them before building the migrate URL.
Example fix
// before dsn := "postgres://user:pass@host/db?x-migrations-table-quoted=yes" // after dsn := "postgres://user:pass@host/db?x-migrations-table-quoted=true"
Defensive patterns
Strategy: validation
Validate before calling
// validate DSN option before pgx.Open
u, err := url.Parse(dsn)
if err != nil { return err }
if v := u.Query().Get("x-migrations-table-quoted"); v != "" {
if _, err := strconv.ParseBool(v); err != nil {
return fmt.Errorf("x-migrations-table-quoted must be a Go boolean (true/false/1/0/t/f), 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 errors.Is(err, ...) || strings.Contains(err.Error(), "unable to parse option x-migrations-table-quoted") {
return fmt.Errorf("fix DSN: x-migrations-table-quoted accepts only Go booleans: %w", err)
} Prevention
- Only ever write true/false or 1/0 for x-* boolean DSN options
- Build the migrate DSN from typed booleans via url.Values, not string templates
- Add a unit test that parses every composed DSN with url.ParseQuery
When it happens
Trigger: Calling pgx.Open or pgxv5.WithInstance (via Open) with a DSN whose query string contains `x-migrations-table-quoted=<something>` where <something> is not a strconv.ParseBool-compatible value, e.g. `x-migrations-table-quoted=yes`, `x-migrations-table-quoted=on`, `x-migrations-table-quoted=TRUE ` with whitespace, or `x-migrations-table-quoted=` followed by typos.
Common situations: Developers copying PostgreSQL-style boolean syntax (on/off, yes/no) into the migrate DSN; templated config files substituting YAML/JSON booleans (true/false is fine, but Yes/On is not); URL-encoding issues that mangle the value; mixing documentation for other drivers into the pgx DSN.
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-multi-statement: %w
- x-migrations-table must be quoted (for instance '"migrate"."
- unknown lock strategy "%s"
- no database name
- no schema
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/894ec4f8bf10abbd.
Report an issue: GitHub.