googleapis/mcp-toolbox · error
sql.Open: %w
Error message
sql.Open: %w
What it means
initTiDBConnectionPool wraps sql.Open failures when constructing the TiDB connection pool. sql.Open only validates the driver name and DSN format — it does not connect — so this almost always indicates a malformed DSN or the mysql driver not being registered. The raw error is preserved with %w.
Source
Thrown at internal/sources/tidb/tidb.go:206
match, err := regexp.MatchString(pattern, host)
if err != nil {
return false
}
return match
}
func initTiDBConnectionPool(ctx context.Context, tracer trace.Tracer, name, host, port, user, pass, dbname string, useSSL bool) (*sql.DB, error) {
//nolint:all // Reassigned ctx
ctx, span := sources.InitConnectionSpan(ctx, tracer, SourceType, name)
defer span.End()
// Configure the driver to connect to the database
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true&charset=utf8mb4&tls=%t", user, pass, host, port, dbname, useSSL)
// Interact with the driver directly as you normally would
pool, err := sql.Open("mysql", dsn)
if err != nil {
return nil, fmt.Errorf("sql.Open: %w", err)
}
return pool, nil
}
View on GitHub (pinned to 8cc6e09de2)
Solutions
- URL-escape credentials with url.UserPassword or url.QueryEscape before building the DSN
- Verify TiDB source config fields: host, port (typically 4000), user, password, database are all set and valid
- Check the wrapped error for which DSN component the driver rejected
- If the driver is unregistered, ensure the mysql driver package is imported
Example fix
// before
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", user, pass, host, port, dbname)
// after
dsn := fmt.Sprintf("%s@tcp(%s:%s)/%s?parseTime=true", url.UserPassword(user, pass), host, port, dbname) Defensive patterns
Strategy: validation
Validate before calling
func validateTiDBConfig(host, port, user, pass, dbname string) error {
if host == "" || port == "" || user == "" || dbname == "" { return errors.New("tidb: host, port, user and database are required") }
if _, err := strconv.Atoi(port); err != nil { return fmt.Errorf("tidb: invalid port %q", port) }
if strings.ContainsAny(pass, "@:/") && url.QueryEscape(pass) == pass == false { /* escape below */ }
_ = url.UserPassword(user, pass) // rejects invalid characters
return nil
} Try / catch
pool, err := initTiDBConnectionPool(...)
if err != nil {
return fmt.Errorf("sql.Open failed: %w", err) // inspect wrapped driver message for bad DSN component
} Prevention
- Escape user/password with url.UserPassword before DSN composition
- Validate numeric port (default 4000) and non-empty database name at config load time
- Smoke-test the DSN with a minimal Go program or mysql CLI before wiring into toolbox
- Keep special characters out of credentials or quote/escape them consistently
When it happens
Trigger: Config.Initialize -> initTiDBConnectionPool where the composed DSN (user:pass@tcp(host:port)/dbname with parseTime, charset and tls params) is rejected by the mysql driver, e.g. invalid characters in user/password or unparseable DSN fields.
Common situations: Password containing special characters (@, :, /) that are not url-escaped before DSN composition; missing or malformed host/port from YAML config; empty dbname producing an invalid DSN.
Related errors
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/3c6c68cf25b16a49.
Report an issue: GitHub.