gastownhall/beads · error

server not reachable: %w

Error message

server not reachable: %w

What it means

After sql.Open succeeds, openDoltDB verifies the Dolt server is actually reachable with a 5-second-timeout PingContext, closing the DB handle on failure. This error wraps the ping failure, so the wrapped error contains the real cause: connection refused, timeout, auth failure, TLS mismatch, or unknown database.

Source

Thrown at cmd/bd/doctor/dolt.go:74

		TLS:      cfg.GetDoltServerTLS(),
	}.String()

	db, err := sql.Open("mysql", connStr)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to open server connection: %w", err)
	}

	db.SetMaxOpenConns(2)
	db.SetMaxIdleConns(1)
	db.SetConnMaxLifetime(30 * time.Second)

	// Verify connectivity
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := db.PingContext(ctx); err != nil {
		_ = db.Close() // Best effort cleanup
		return nil, nil, fmt.Errorf("server not reachable: %w", err)
	}

	return db, cfg, nil
}

// doltConn holds an open Dolt connection.
// Used by doctor checks to coordinate database access.
type doltConn struct {
	db   *sql.DB
	cfg  *configfile.Config // config for server detail (host:port)
	port int                // resolved port (from doltserver.DefaultConfig, not cfg fallback)
}

// Close releases the database connection.
func (c *doltConn) Close() {
	_ = c.db.Close()
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Confirm the server is running and the resolved port is correct: check the port file in the .beads dir and the server process/log; restart via any bd command.
  2. Inspect the wrapped %w error for the exact cause (connection refused vs. timeout vs. "Access denied" vs. "Unknown database") and fix accordingly — credentials, database name, or TLS settings in config.yaml.
  3. Increase tolerance for slow startup by retrying `bd doctor` after a few seconds if the server was just auto-started.

Example fix

// before
bd doctor
// error: server not reachable: dial tcp 127.0.0.1:32111: connect: connection refused
// after
bd list   # restarts the Dolt server on the correct port
bd doctor
Defensive patterns

Strategy: retry

Validate before calling

dsCfg := doltserver.DefaultConfig(beadsDir)
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", dsCfg.Host, dsCfg.Port), 2*time.Second)
if err != nil {
    return fmt.Errorf("dolt server not listening on %s:%d; run any bd command", dsCfg.Host, dsCfg.Port)
}
conn.Close()

Try / catch

db, err := openDoltDB(beadsDir)
if err != nil && strings.Contains(err.Error(), "server not reachable") {
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() {
        // retry after allowing server startup
    }
    return err
}

Prevention

When it happens

Trigger: Calling openDoltDB (via openDoltConn or querySQLRemotes) when db.PingContext fails within 5s: the Dolt server is not listening on the resolved port, it just crashed or is still starting, credentials are wrong, TLS is required/mismatched, or the configured database does not exist on the server.

Common situations: Stale port file pointing at a port where the server no longer listens; server still booting after auto-start (race); wrong password in credentials file vs BEADS_DOLT_PASSWORD env; externally hosted server with TLS config mismatch; firewall blocking localhost/remote port.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/1a42c2f2a4824c5a. Report an issue: GitHub.