{"record":{"id":"5ec9f729ea75fc2a","repo":"Mintplex-Labs/anything-llm","slug":"uri-must-start-with-this-scheme","errorCode":null,"errorMessage":"URI must start with '${this.scheme}://'","messagePattern":"URI must start with '(.+?)://'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/utils.js","lineNumber":110,"sourceCode":"        \"(?:([^:@,/?=&]+)(?::([^:@,/?=&]+))?@)?\" + // User (Group 2) and Password (Group 3)\n        \"([^@/?=&]+)\" + // Host address(es) (Group 4)\n        \"(?:/([^:@,/?=&]+)?)?\" + // Endpoint (Group 5)\n        \"(?:\\\\?([^:@,/?]+)?)?\" + // Options (Group 6)\n        \"\\\\s*$\", // Optional whitespace padding at the end of the line\n      \"gi\"\n    );\n    const connectionStringObject = {};\n\n    if (!uri.includes(\"://\")) {\n      throw new Error(`No scheme found in URI ${uri}`);\n    }\n\n    const tokens = connectionStringParser.exec(uri);\n\n    if (Array.isArray(tokens)) {\n      connectionStringObject.scheme = tokens[1];\n      if (this.scheme && this.scheme !== connectionStringObject.scheme) {\n        throw new Error(`URI must start with '${this.scheme}://'`);\n      }\n      connectionStringObject.username = tokens[2]\n        ? decodeURIComponent(tokens[2])\n        : tokens[2];\n      connectionStringObject.password = tokens[3]\n        ? decodeURIComponent(tokens[3])\n        : tokens[3];\n      connectionStringObject.hosts = this._parseAddress(tokens[4]);\n      connectionStringObject.endpoint = tokens[5]\n        ? decodeURIComponent(tokens[5])\n        : tokens[5];\n      connectionStringObject.options = tokens[6]\n        ? this._parseOptions(tokens[6])\n        : tokens[6];\n    }\n    return connectionStringObject;\n  }\n","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/utils/agents/aibitat/plugins/sql-agent/SQLConnectors/utils.js#L92-L128","documentation":"Thrown by ConnectionStringParser.parse when the URI does contain a scheme but it differs from the scheme the parser instance was constructed with. Unlike the no-scheme case, parsing succeeded far enough to extract tokens[1]; the mismatch check then rejects it so a MySQL-typed parser never hands back a PostgreSQL-shaped object.","triggerScenarios":"Parsing 'postgresql://user@host/db' with a parser built for scheme 'mysql'; a stored agent SQL connection whose engine key and connection string disagree; using scheme aliases like 'postgres://' or 'sqlserver://' against a parser expecting the canonical string.","commonSituations":"Switching a connection's engine in settings without updating the stored URI; aliases ('postgres' vs 'postgresql') that pass user review but fail exact comparison; mixed config sources where one field was migrated and the other was not.","solutions":["Align the URI scheme with the connector's expected scheme exactly (postgresql:// for PostgreSQL, mysql:// for MySQL, sqlserver:// for SQL Server per the parser's construction).","Expand aliases before parsing: replace /^postgres:\\/\\// with 'postgresql://' and /^mssql:\\/\\// with 'sqlserver://'.","Store engine and URI together and validate them as a pair when saving agent SQL connections."],"exampleFix":"// before\nconst p = new ConnectionStringParser({ scheme: \"postgresql\" });\np.parse(\"postgres://user@host/db\");  // throws: URI must start with 'postgresql://'\n\n// after\np.parse(\"postgresql://user@host/db\");","handlingStrategy":"validation","validationCode":"const SCHEME_ALIASES = { postgres: \"postgresql\", mssql: \"sqlserver\", \"sql-server\": \"sqlserver\" };\nfunction normalizeUriScheme(uri, expected) {\n  let u = uri.trim();\n  const m = u.match(/^([a-z-]+):\\/\\//i);\n  if (!m) throw new Error(`No scheme found in URI ${u}`);\n  const canonical = SCHEME_ALIASES[m[1].toLowerCase()] ?? m[1].toLowerCase();\n  if (canonical !== expected) throw new Error(`URI scheme '${m[1]}' does not match connector '${expected}'`);\n  return canonical + \"://\" + u.slice(m[0].length);\n}","typeGuard":"/** @returns {boolean} */\nfunction uriStartsWithScheme(uri, scheme) {\n  return typeof uri === \"string\" && uri.trim().toLowerCase().startsWith(`${scheme}://`);\n}","tryCatchPattern":"try {\n  const parsed = parser.parse(uri);\n} catch (e) {\n  if (e.message.includes(\"URI must start with\")) {\n    parsed = parser.parse(uri.replace(/^postgres:\\/\\//i, \"postgresql://\")); // alias fix, retry\n  } else throw e;\n}","preventionTips":["Canonicalize scheme aliases (postgres->postgresql, mssql->sqlserver) at config load.","Validate that the stored engine key and the URI scheme agree before parsing.","Surface both expected and actual scheme in your own config errors to make drift obvious."],"tags":["sql-agent","connection-string","scheme","uri-parsing"],"backgroundTag":"connection-string-scheme-mismatch","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}