benbjohnson/litestream · error

open database: %w

Error message

open database: %w

What it means

In generateLoad, `sql.Open("sqlite3", c.DB+"?_journal_mode=WAL")` failed and the error is wrapped as "open database". Note that database/sql's Open is lazy and mostly validates the DSN/driver; real connection failures usually surface on first use, so this error typically indicates a bad DSN, an unregistered driver (build-tag/CGO issue with the sqlite3 driver), or an immediate driver-level open failure.

Source

Thrown at cmd/litestream-test/load.go:80

	}

	slog.Info("Starting load generation",
		"db", c.DB,
		"write_rate", c.WriteRate,
		"duration", c.Duration,
		"pattern", c.Pattern,
		"payload_size", c.PayloadSize,
		"read_ratio", c.ReadRatio,
		"workers", c.Workers,
	)

	return c.generateLoad(ctx)
}

func (c *LoadCommand) generateLoad(ctx context.Context) error {
	db, err := sql.Open("sqlite3", c.DB+"?_journal_mode=WAL")
	if err != nil {
		return fmt.Errorf("open database: %w", err)
	}
	defer db.Close()

	db.SetMaxOpenConns(c.Workers + 1)
	db.SetMaxIdleConns(c.Workers)

	if err := c.ensureTestTable(db); err != nil {
		return fmt.Errorf("ensure test table: %w", err)
	}

	ctx, cancel := context.WithTimeout(ctx, c.Duration)
	defer cancel()

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-sigChan
		slog.Info("Received interrupt signal, stopping load generation")

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check that the -db path is valid, readable, and contains no characters (like '?') that would break the DSN; rename or quote/escape if needed.
  2. Verify the binary was built with the sqlite3 driver imported (blank import of the driver package); rebuild with CGO or the driver's pure-Go variant as required.
  3. Run `litestream-test load -db <path>` on a known-good database (created by populate) to isolate DSN vs environment issues.

Example fix

// before
db, err := sql.Open("sqlite3", c.DB+"?_journal_mode=WAL")
if err != nil {
    return fmt.Errorf("open database: %w", err)
}
// after — surface driver/DSN issues eagerly with a ping
db, err := sql.Open("sqlite3", c.DB+"?_journal_mode=WAL")
if err != nil {
    return fmt.Errorf("open database: %w", err)
}
if err := db.Ping(); err != nil {
    return fmt.Errorf("open database: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check the path and DSN before invoking
if (dbPath.includes("?")) throw new Error("DB path must not contain DSN-significant characters: " + dbPath);

Try / catch

try {
  await run("litestream-test", ["load", "-db", dbPath]);
} catch (e) {
  if (String(e).includes("open database")) {
    console.error(`Failed to open ${dbPath}: check the sqlite3 driver build (CGO/pure-Go) and that the path is DSN-safe`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `litestream-test load -db <path>` where the resulting DSN `<path>?_journal_mode=WAL` is rejected by the driver, the sqlite3 driver is not imported/available in the binary, or the driver immediately fails to open the file (e.g., unreadable path).

Common situations: Special characters in the DB path corrupting the DSN; a build without the sqlite3 driver registered; file permissions blocking the driver's open; very unusual DSN combos when the path itself contains '?' or other DSN-significant characters.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/635b9b30d8187543. Report an issue: GitHub.