golang-migrate/migrate · error
"%s" MigrationsTable contains too many dot characters
Error message
"%s" MigrationsTable contains too many dot characters
What it means
When Config.MigrationsTable is quoted (contains double-quoted identifiers per the quoting convention), pgx v5's WithInstance parses it with the regex `"(.*?)"` and accepts at most two matches: schema name plus table name. If more than two quoted segments are found — i.e. the value contains too many dot-separated quoted parts — WithInstance returns this error because a migrations table can only be schema-qualified one level deep.
Source
Thrown at database/pgx/v5/pgx.go:116
}
config.SchemaName = schemaName
}
if len(config.MigrationsTable) == 0 {
config.MigrationsTable = DefaultMigrationsTable
}
config.migrationsSchemaName = config.SchemaName
config.migrationsTableName = config.MigrationsTable
if config.MigrationsTableQuoted {
re := regexp.MustCompile(`"(.*?)"`)
result := re.FindAllStringSubmatch(config.MigrationsTable, -1)
config.migrationsTableName = result[len(result)-1][1]
if len(result) == 2 {
config.migrationsSchemaName = result[0][1]
} else if len(result) > 2 {
return nil, fmt.Errorf("\"%s\" MigrationsTable contains too many dot characters", config.MigrationsTable)
}
}
conn, err := instance.Conn(context.Background())
if err != nil {
return nil, err
}
px := &Postgres{
conn: conn,
db: instance,
config: config,
}
if err := px.ensureVersionTable(); err != nil {
return nil, err
}View on GitHub (pinned to 01a9643f14)
Solutions
- Use at most two quoted segments: "schema"."table" — drop the database/catalog part.
- If the table lives in the default schema, use a single quoted segment: "table".
- Log the exact MigrationsTable string and count the quoted groups before calling WithInstance.
- Validate in your config loader that strings.Matches of `"(.*?)"` number 1 or 2.
Example fix
// before cfg.MigrationsTable = `"mydb"."myschema"."schema_migrations"` // 3 parts // after cfg.MigrationsTable = `"myschema"."schema_migrations"`
Defensive patterns
Strategy: validation
Validate before calling
re := regexp.MustCompile(`"(.*?)"`)
if n := len(re.FindAllStringSubmatch(cfg.MigrationsTable, -1)); n > 2 {
return fmt.Errorf("MigrationsTable %q may contain at most schema+table quoted parts", cfg.MigrationsTable)
} Type guard
func isWellFormedMigrationsTable(name string) bool {
return len(regexp.MustCompile(`"(.*?)"`).FindAllStringSubmatch(name, -1)) <= 2
} Try / catch
drv, err := pgxv5.WithInstance(conn, cfg)
if err != nil {
if strings.Contains(err.Error(), "too many dot characters") {
return fmt.Errorf(`use "schema"."table" (max two quoted parts), got %s: %w`, cfg.MigrationsTable, err)
}
return err
} Prevention
- Format quoted migrations tables as "schema"."table" only — never include the database part
- Strip stray double quotes when generating table names programmatically
- Unit-test table-name parsing with the same regex the driver uses
When it happens
Trigger: Passing Config{MigrationsTable: `"a"."b"."c"`} (three quoted parts) to pgxv5.WithInstance, or a value with stray quoted segments such as `"weird""name"."tbl"` producing three regex matches; also reachable via Open when it delegates to WithInstance.
Common situations: Misunderstanding the quoting format and quoting each dot separately ("a"."."."b"); copying a fully-qualified name including database/catalog (db.schema.table) from pg_admin and quoting all three parts; programmatic generation of table names that joins too many quoted identifiers.
Related errors
- x-migrations-table must be quoted (for instance '"migrate"."
- unable to parse option x-multi-statement: %w
- unable to parse option x-migrations-table-quoted: %w
- unknown lock strategy "%s"
- no database name
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/27b691b0cc8c6aca.
Report an issue: GitHub.