ory/hydra · error

invalid DSN: empty scheme

Error message

invalid DSN: empty scheme

What it means

After cutting a DSN on '://', ExtractSchemeFromDSN checks that the part before the separator is non-empty. A string like ':///path/db' has a separator but no scheme, so the database driver still cannot be identified and the function returns this error.

Source

Thrown at oryx/sqlxx/sqlxx.go:90

func OnConflictDoNothing(dialect string, columnNoop string) string {
	if dialect == "mysql" {
		return fmt.Sprintf(" ON DUPLICATE KEY UPDATE `%s` = `%s` ", columnNoop, columnNoop)
	} else {
		return ` ON CONFLICT DO NOTHING `
	}
}

// ExtractSchemeFromDSN returns the scheme (e.g. `mysql`, `postgres`, etc) component in a DSN string,
// as well as the remaining part of the DSN after the scheme separator.
// It is an error to not have a scheme present.
// This makes sense in the context of a DSN to be able to identify which database is in use.
func ExtractSchemeFromDSN(dsn string) (string, string, error) {
	scheme, afterSchemeSeparator, schemeSeparatorFound := strings.Cut(dsn, "://")
	if !schemeSeparatorFound {
		return "", "", errors.New("invalid DSN: missing scheme separator")
	}
	if scheme == "" {
		return "", "", errors.New("invalid DSN: empty scheme")
	}

	return scheme, afterSchemeSeparator, nil
}

// ExtractDbNameFromDSN returns the database name component in a DSN string.
func ExtractDbNameFromDSN(dsn string) (string, error) {
	_, afterScheme, err := ExtractSchemeFromDSN(dsn)
	if err != nil {
		return "", err
	}

	_, afterSlash, slashFound := strings.Cut(afterScheme, "/")
	if !slashFound {
		return "", nil
	}

	dbName, _, _ := strings.Cut(afterSlash, "?")

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Ensure the scheme (postgres, mysql, sqlite, etc.) precedes '://' in the DSN
  2. Re-check the code path building the DSN string so the scheme is always prepended
  3. Log or validate the full DSN (redacted) at configuration load time
  4. Use package-provided constructors or constants for DSN schemes instead of manual strings

Example fix

// before
dsn := "///var/lib/db.sqlite3"
// after
dsn := "sqlite:///var/lib/db.sqlite3"
Defensive patterns

Strategy: validation

Validate before calling

scheme, _, ok := strings.Cut(dsn, "://")
if !ok || scheme == "" {
	return fmt.Errorf("DSN %q has an empty scheme", redact(dsn))
}

Type guard

func dsnSchemePresent(dsn string) bool {
	scheme, _, ok := strings.Cut(dsn, "://")
	return ok && scheme != ""
}

Try / catch

scheme, rest, err := sqlxx.ExtractSchemeFromDSN(dsn)
if err != nil {
	return nil, fmt.Errorf("invalid DSN scheme: %w", err)
}

Prevention

When it happens

Trigger: Calling ExtractSchemeFromDSN (or its callers SQLiteDirFromDSN, ExtractDbNameFromDSN, ReplaceSchemeInDSN, DSNRedacted) with a DSN starting with '://' or with an empty scheme before '://', e.g. ':///var/lib/db.sqlite3'.

Common situations: String concatenation or template interpolation that dropped the scheme prefix (e.g. fmt.Sprintf("://%s", host)); env var values where the scheme portion was deleted during editing; URL parsing that stripped the scheme before reassembling the DSN.

Related errors


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/a27a1aac7be60ebd. Report an issue: GitHub.