gastownhall/beads · error
ensure global db: failed to open connection: %w
Error message
ensure global db: failed to open connection: %w
What it means
EnsureGlobalDatabase wraps any error from sql.Open("mysql", dsn) with this message. sql.Open only validates the DSN and loads the driver — it does not touch the network — so this almost always means the DSN string is malformed (bad characters in user/password/host) or the mysql driver failed to register/initialize. It does NOT mean the server is down; that surfaces later as the 'server not reachable' ping error.
Source
Thrown at internal/doltserver/doltserver.go:1537
// beads_global database if it doesn't already exist. This is idempotent and
// safe to call on every shared server init. Schema initialization and config
// seeding (issue prefix, project ID) are handled by the store layer when the
// global database is first opened with CreateIfMissing=true.
//
// Returns nil if the database already exists or was successfully created.
func EnsureGlobalDatabase(host string, port int, user, password string) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
dsn := doltutil.ServerDSN{
Host: host,
Port: port,
User: user,
Password: password,
}.String()
db, err := sql.Open("mysql", dsn)
if err != nil {
return fmt.Errorf("ensure global db: failed to open connection: %w", err)
}
defer db.Close()
db.SetMaxOpenConns(1)
db.SetConnMaxLifetime(10 * time.Second)
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("ensure global db: server not reachable: %w", err)
}
// CREATE DATABASE IF NOT EXISTS is idempotent — safe on every call.
// GlobalDatabaseName is a constant ("beads_global"), not user input.
_, err = db.ExecContext(ctx, fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`", GlobalDatabaseName)) //nolint:gosec // G201: constant database name
if err != nil {
errLower := strings.ToLower(err.Error())
if !strings.Contains(errLower, "database exists") && !strings.Contains(errLower, "1007") {
return fmt.Errorf("ensure global db: failed to create %s: %w", GlobalDatabaseName, err)
}
}View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped error text for 'invalid DSN' and URL-escape credentials containing @ : / ( ) characters
- Verify host/port/user/password values in bd config are clean (no stray quotes or whitespace)
- Re-check credentials: temporary password with special chars from an automated setup is the usual culprit
- If the driver is missing in a forked build, add _ "github.com/go-sql-driver/mysql" to imports
- If Open still fails with valid DSN, retry once — transient driver init failures are rare; persistent ones indicate a broken binary
Example fix
// before: raw password breaks the DSN
// password := "p@ss:word" // DSN parse error
// after: escape credentials before building the DSN
dsnUser := url.QueryEscape(user)
dsnPassword := url.QueryEscape(password)
dsn := doltutil.ServerDSN{Host: host, Port: port, User: dsnUser, Password: dsnPassword}.String() Defensive patterns
Strategy: validation
Validate before calling
// Validate credentials can form a clean DSN before calling EnsureGlobalDatabase
func validDSNPart(s string) bool {
if s == "" { return true }
for _, r := range s {
if strings.ContainsRune("@:/(", r) { return false }
}
return true
}
if !validDSNPart(user) || !validDSNPart(password) {
return errors.New("db user/password contain DSN metacharacters; escape or change them")
} Try / catch
if err := doltserver.EnsureGlobalDatabase(host, port, user, password); err != nil {
var dsnErr *error
if strings.Contains(err.Error(), "failed to open connection") {
return fmt.Errorf("bad DSN (check special chars in user/password): %w", err)
}
_ = dsnErr
return err
} Prevention
- Avoid @ : / ( ) in database credentials; URL-escape if unavoidable
- Keep credentials in env vars/config, never inline in code
- Ensure go-sql-driver/mysql is imported in any custom build
- Sanitize config files for stray quotes/whitespace in credential fields
When it happens
Trigger: sql.Open("mysql", dsn) returns an error when EnsureGlobalDatabase builds a ServerDSN from host, port, user, password — typically an invalid DSN (unescaped special characters like @, :, /, ( in user or password), or the go-sql-driver/mysql driver not imported/registered.
Common situations: Password or username containing DSN metacharacters (@ : / ( ) set in BEADS_DB_PASSWORD or config) without escaping; config file with stray whitespace/quotes in credentials; a build missing the mysql driver blank import.
Related errors
- flush: failed to open connection: %w
- open gc connection: %w
- acquire gc connection: %w
- failed to parse DSN for migration connection: %w
- failed to open ignored tx connection: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/fe040344f3ab95d8.
Report an issue: GitHub.