gastownhall/beads · error
failed to parse DSN for migration connection: %w
Error message
failed to parse DSN for migration connection: %w
What it means
openMigrationDB parses the store's connection string with mysql.ParseDSN before opening a dedicated long-timeout migration connection; this error wraps a DSN parse failure. It is a configuration problem: the connection string is malformed, not a server-side issue.
Source
Thrown at internal/storage/dolt/store.go:2743
// per-database advisory lock, with retry for transient lock contention.
// Implements storage.SchemaMigrator.
func (s *DoltStore) ApplySchemaMigrations(ctx context.Context) (int, error) {
migDB, err := s.openMigrationDB()
if err != nil {
return 0, err
}
defer migDB.Close()
return initSchemaOnDBWithRetry(ctx, migDB)
}
// openMigrationDB opens a one-off connection pool for schema migrations with no
// read/write timeout. Migrations may run far longer than the default 10s pool
// timeout, and timing out part-way leaves the database in a dirty, half-migrated
// state. The single connection is closed by the caller once migration completes.
func (s *DoltStore) openMigrationDB() (*sql.DB, error) {
cfg, err := mysql.ParseDSN(s.connStr)
if err != nil {
return nil, fmt.Errorf("failed to parse DSN for migration connection: %w", err)
}
cfg.ReadTimeout = 0
cfg.WriteTimeout = 0
db, err := sql.Open("mysql", cfg.FormatDSN())
if err != nil {
return nil, fmt.Errorf("failed to open migration connection: %w", err)
}
db.SetMaxOpenConns(1)
return db, nil
}
// rebuildPoolAfterMigration replaces the main connection pool (s.db) after a
// migrating open. Migrations run over a separate one-off pool
// (openMigrationDB); a connection already pooled in s.db before migrations
// ran (e.g. the startup Ping in newServerMode) stays pinned to the
// pre-migration Dolt session root, so the first read through it returns 0
// rows / table-not-found and does not self-heal on retry (be-itm5). A
// non-migrating open (applied == 0 — the common re-open-of-an-View on GitHub (pinned to 71377f2769)
Solutions
- Fix the DSN string: correct form is user:pass@tcp(host:port)/dbname?params
- URL-escape or cfg-escape special characters in the password (e.g. use url.QueryEscape for the password portion when building the DSN)
- Use mysql.Config + cfg.FormatDSN() in code instead of hand-writing the string
- Check the environment variable / config file supplying the connection string for truncation or quoting artifacts
Example fix
// before connStr := "root:p@ss@tcp(localhost:3306)/beads" // after connStr := "root:p%40ss@tcp(localhost:3306)/beads"
Defensive patterns
Strategy: validation
Validate before calling
// validate the DSN before constructing the store
func validateDSN(connStr string) error {
cfg, err := mysql.ParseDSN(connStr)
if err != nil {
return fmt.Errorf("invalid DSN: %w", err)
}
if cfg.DBName == "" {
return errors.New("DSN missing database name")
}
return nil
} Prevention
- Build DSNs with mysql.Config.FormatDSN(), never string concatenation
- Escape special characters in passwords
- Validate the env-provided DSN at startup, before first use
- Store DSNs without surrounding quotes/whitespace from config files
When it happens
Trigger: Creating a DoltStore with s.connStr that mysql.ParseDSN rejects — malformed format (wrong scheme, bad net address, unterminated brackets), invalid parameter, or characters that need escaping (e.g. special chars in password like '@' or '/' unescaped).
Common situations: Password containing '@', '(', '/' or spaces placed raw into user:pass@tcp(...)/ DSN; env var BEADS_DSN missing or set to a non-DSN value; copy-pasted URI-style 'mysql://user:pass@host/db' which ParseDSN does not accept directly.
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
- ensure global db: failed to open connection: %w
- flush: failed to open connection: %w
- open gc connection: %w
- failed to parse DSN for long-timeout connection: %w
- rebuild pool after migration: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/01d54f1eddb1aa56.
Report an issue: GitHub.