ory/hydra · error

invalid DSN: missing scheme separator

Error message

invalid DSN: missing scheme separator

What it means

ExtractSchemeFromDSN splits a DSN on the '://' separator and errors when no scheme is present. A DSN like 'postgres://...' yields scheme 'postgres'; a bare 'mydbhost/db' fails because the database type cannot be identified. This guard keeps downstream parsing from misinterpreting the DSN.

Source

Thrown at oryx/sqlxx/sqlxx.go:87

	return strings.Join(statements, ", ")
}

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

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Prefix the DSN with its proper scheme, e.g. 'postgres://' or 'sqlite://'
  2. Check the environment variable / config key supplying the DSN for a missing scheme
  3. Validate DSNs at startup with ExtractSchemeFromDSN and fail fast with a clear message
  4. If a file path is intended for SQLite, use the 'sqlite://' scheme followed by the path

Example fix

// before
dsn := "localhost:5432/mydb"
// after
dsn := "postgres://localhost:5432/mydb"
Defensive patterns

Strategy: validation

Validate before calling

if !strings.Contains(dsn, "://") {
	return fmt.Errorf("DSN %q must include a scheme, e.g. postgres://...", redact(dsn))
}

Type guard

func hasDSNScheme(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("bad DSN (missing scheme?): %w", err)
}

Prevention

When it happens

Trigger: Calling ExtractSchemeFromDSN (directly or via SQLiteDirFromDSN, ExtractDbNameFromDSN, ReplaceSchemeInDSN, DSNRedacted) with a DSN string that lacks '://', e.g. 'sqlite:///path/db' is fine but 'localhost:5432/db' or a bare file path is not.

Common situations: Env vars (DSN/DB_URL) set to a hostname or file path without a scheme; config values migrated from tools that accept scheme-less connection strings; shell quoting stripping part of the URL; accidentally passing a database name instead of a full DSN.

Related errors


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