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

  1. Use at most two quoted segments: "schema"."table" — drop the database/catalog part.
  2. If the table lives in the default schema, use a single quoted segment: "table".
  3. Log the exact MigrationsTable string and count the quoted groups before calling WithInstance.
  4. 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

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


AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02). Data as JSON: /api/errors/27b691b0cc8c6aca. Report an issue: GitHub.