{"record":{"id":"a27a1aac7be60ebd","repo":"ory/hydra","slug":"invalid-dsn-empty-scheme","errorCode":null,"errorMessage":"invalid DSN: empty scheme","messagePattern":"invalid DSN: empty scheme","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oryx/sqlxx/sqlxx.go","lineNumber":90,"sourceCode":"func OnConflictDoNothing(dialect string, columnNoop string) string {\n\tif dialect == \"mysql\" {\n\t\treturn fmt.Sprintf(\" ON DUPLICATE KEY UPDATE `%s` = `%s` \", columnNoop, columnNoop)\n\t} else {\n\t\treturn ` ON CONFLICT DO NOTHING `\n\t}\n}\n\n// ExtractSchemeFromDSN returns the scheme (e.g. `mysql`, `postgres`, etc) component in a DSN string,\n// as well as the remaining part of the DSN after the scheme separator.\n// It is an error to not have a scheme present.\n// This makes sense in the context of a DSN to be able to identify which database is in use.\nfunc ExtractSchemeFromDSN(dsn string) (string, string, error) {\n\tscheme, afterSchemeSeparator, schemeSeparatorFound := strings.Cut(dsn, \"://\")\n\tif !schemeSeparatorFound {\n\t\treturn \"\", \"\", errors.New(\"invalid DSN: missing scheme separator\")\n\t}\n\tif scheme == \"\" {\n\t\treturn \"\", \"\", errors.New(\"invalid DSN: empty scheme\")\n\t}\n\n\treturn scheme, afterSchemeSeparator, nil\n}\n\n// ExtractDbNameFromDSN returns the database name component in a DSN string.\nfunc ExtractDbNameFromDSN(dsn string) (string, error) {\n\t_, afterScheme, err := ExtractSchemeFromDSN(dsn)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t_, afterSlash, slashFound := strings.Cut(afterScheme, \"/\")\n\tif !slashFound {\n\t\treturn \"\", nil\n\t}\n\n\tdbName, _, _ := strings.Cut(afterSlash, \"?\")","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/sqlxx/sqlxx.go#L72-L108","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","solutions":["Ensure the scheme (postgres, mysql, sqlite, etc.) precedes '://' in the DSN","Re-check the code path building the DSN string so the scheme is always prepended","Log or validate the full DSN (redacted) at configuration load time","Use package-provided constructors or constants for DSN schemes instead of manual strings"],"exampleFix":"// before\ndsn := \"///var/lib/db.sqlite3\"\n// after\ndsn := \"sqlite:///var/lib/db.sqlite3\"","handlingStrategy":"validation","validationCode":"scheme, _, ok := strings.Cut(dsn, \"://\")\nif !ok || scheme == \"\" {\n\treturn fmt.Errorf(\"DSN %q has an empty scheme\", redact(dsn))\n}","typeGuard":"func dsnSchemePresent(dsn string) bool {\n\tscheme, _, ok := strings.Cut(dsn, \"://\")\n\treturn ok && scheme != \"\"\n}","tryCatchPattern":"scheme, rest, err := sqlxx.ExtractSchemeFromDSN(dsn)\nif err != nil {\n\treturn nil, fmt.Errorf(\"invalid DSN scheme: %w\", err)\n}","preventionTips":["Build DSNs with fmt.Sprintf(\"%s://%s\", scheme, rest) so the scheme is never dropped","Never strip the scheme when reassembling parsed URLs into DSNs","Sanity-check scheme emptiness when accepting DSNs from user input"],"tags":["go","dsn","database","validation"],"backgroundTag":"invalid-dsn","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}