golang-migrate/migrate · error
x-migrations-table must be quoted (for instance '"migrate"."
Error message
x-migrations-table must be quoted (for instance '"migrate"."schema_migrations"') when x-migrations-table-quoted is enabled, current value is: %s
What it means
golang-migrate requires that when x-migrations-table-quoted=true, the x-migrations-table value must be a fully double-quoted Postgres identifier (starting and ending with "), e.g. "migrate"."schema_migrations". If a migrations table is set but the first or last character is not a quote, Open rejects the URL. This guards against accidentally treating an unquoted identifier as a quoted one.
Source
Thrown at database/pgx/v5/pgx.go:164
// 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/v5", 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)
if err != nil {
return nil, err
}
if multiStatementMaxSize <= 0 {View on GitHub (pinned to 01a9643f14)
Solutions
- Wrap the migrations table value in double quotes, including the schema if present: x-migrations-table="migrate"."schema_migrations"
- Ensure quotes survive URL encoding/shell quoting — use single-quoted shell strings or percent-encode (%22)
- Set x-migrations-table-quoted=false if the table name does not need case-sensitivity or special characters
- Drop x-migrations-table-quoted entirely when using a plain unquoted table name
Example fix
// before dsn := "postgres://u:p@host/db?x-migrations-table=migrate.schema_migrations&x-migrations-table-quoted=true" // after dsn := `postgres://u:p@host/db?x-migrations-table="migrate"."schema_migrations"&x-migrations-table-quoted=true`
Defensive patterns
Strategy: validation
Validate before calling
u, _ := url.Parse(dsn)
q := u.Query()
tbl := q.Get("x-migrations-table")
if q.Get("x-migrations-table-quoted") == "true" && tbl != "" {
if !strings.HasPrefix(tbl, `"`) || !strings.HasSuffix(tbl, `"`) {
return fmt.Errorf("x-migrations-table must be fully quoted, got %q", tbl)
}
} Type guard
func isFullyQuotedIdentifier(s string) bool {
return len(s) >= 2 && strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`)
} Try / catch
if err := migrateOpen(); err != nil {
if strings.Contains(err.Error(), "x-migrations-table must be quoted") {
log.Fatalf("wrap x-migrations-table in double quotes: %v", err)
}
panic(err)
} Prevention
- When enabling x-migrations-table-quoted, always write the table as "schema"."table"
- Single-quote shell strings containing double quotes to prevent stripping
- Prefer setting MigrationsTable in a Go raw string literal (`...`) over interpolated DSNs
When it happens
Trigger: Open with a URL containing both x-migrations-table=schema_migrations and x-migrations-table-quoted=true, where the table value does not start and end with '"', e.g. ?x-migrations-table=migrate.schema_migrations&x-migrations-table-quoted=true.
Common situations: Enabling the quoted flag but forgetting to wrap the table (and optional schema) in double quotes; JSON/YAML/shell layers stripping the quote characters; copy-pasting a plain table name while adding the new quoted option after upgrading golang-migrate.
Related errors
- no database name
- unable to parse option x-migrations-table-quoted: %w
- unable to parse option x-multi-statement: %w
- "%s" MigrationsTable contains too many dot characters
- unable to parse option x-migrations-table-quoted: %w
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/b3577ba08412b122.
Report an issue: GitHub.