This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new b7a5b24a54 feat(docs): add auto-generated troubleshooting section to 
database pages (#37345)
b7a5b24a54 is described below

commit b7a5b24a54150695db9933a7f9ea4a7916b5468b
Author: Evan Rusackas <[email protected]>
AuthorDate: Thu Jan 22 14:43:02 2026 -0800

    feat(docs): add auto-generated troubleshooting section to database pages 
(#37345)
    
    Co-authored-by: Claude Opus 4.5 <[email protected]>
---
 docs/scripts/extract_custom_errors.py           | 296 ++++++++
 docs/scripts/generate-database-docs.mjs         |  76 ++
 docs/src/components/databases/DatabaseIndex.tsx |  16 +-
 docs/src/components/databases/DatabasePage.tsx  | 130 ++++
 docs/src/components/databases/types.ts          |  12 +
 docs/src/data/databases.json                    | 953 +++++++++++++++++++++++-
 6 files changed, 1473 insertions(+), 10 deletions(-)

diff --git a/docs/scripts/extract_custom_errors.py 
b/docs/scripts/extract_custom_errors.py
new file mode 100644
index 0000000000..35aee1cdbc
--- /dev/null
+++ b/docs/scripts/extract_custom_errors.py
@@ -0,0 +1,296 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Extract custom_errors from database engine specs for documentation.
+
+This script parses engine spec files to extract error handling information
+that can be displayed on database documentation pages.
+
+Usage: python scripts/extract_custom_errors.py
+Output: JSON mapping of engine spec module names to their custom errors
+"""
+
+import ast
+import json  # noqa: TID251 - standalone docs script, not part of superset
+import sys
+from pathlib import Path
+from typing import Any
+
+# Map SupersetErrorType values to human-readable categories and issue codes
+ERROR_TYPE_INFO = {
+    "CONNECTION_INVALID_USERNAME_ERROR": {
+        "category": "Authentication",
+        "description": "Invalid username",
+        "issue_codes": [1012],
+    },
+    "CONNECTION_INVALID_PASSWORD_ERROR": {
+        "category": "Authentication",
+        "description": "Invalid password",
+        "issue_codes": [1013],
+    },
+    "CONNECTION_ACCESS_DENIED_ERROR": {
+        "category": "Authentication",
+        "description": "Access denied",
+        "issue_codes": [1014, 1015],
+    },
+    "CONNECTION_INVALID_HOSTNAME_ERROR": {
+        "category": "Connection",
+        "description": "Invalid hostname",
+        "issue_codes": [1007],
+    },
+    "CONNECTION_PORT_CLOSED_ERROR": {
+        "category": "Connection",
+        "description": "Port closed or refused",
+        "issue_codes": [1008],
+    },
+    "CONNECTION_HOST_DOWN_ERROR": {
+        "category": "Connection",
+        "description": "Host unreachable",
+        "issue_codes": [1009],
+    },
+    "CONNECTION_UNKNOWN_DATABASE_ERROR": {
+        "category": "Connection",
+        "description": "Unknown database",
+        "issue_codes": [1015],
+    },
+    "CONNECTION_DATABASE_PERMISSIONS_ERROR": {
+        "category": "Permissions",
+        "description": "Insufficient permissions",
+        "issue_codes": [1017],
+    },
+    "CONNECTION_MISSING_PARAMETERS_ERROR": {
+        "category": "Configuration",
+        "description": "Missing parameters",
+        "issue_codes": [1018],
+    },
+    "CONNECTION_DATABASE_TIMEOUT": {
+        "category": "Connection",
+        "description": "Connection timeout",
+        "issue_codes": [1001, 1009],
+    },
+    "COLUMN_DOES_NOT_EXIST_ERROR": {
+        "category": "Query",
+        "description": "Column not found",
+        "issue_codes": [1003, 1004],
+    },
+    "TABLE_DOES_NOT_EXIST_ERROR": {
+        "category": "Query",
+        "description": "Table not found",
+        "issue_codes": [1003, 1005],
+    },
+    "SCHEMA_DOES_NOT_EXIST_ERROR": {
+        "category": "Query",
+        "description": "Schema not found",
+        "issue_codes": [1003, 1016],
+    },
+    "SYNTAX_ERROR": {
+        "category": "Query",
+        "description": "SQL syntax error",
+        "issue_codes": [1030],
+    },
+    "OBJECT_DOES_NOT_EXIST_ERROR": {
+        "category": "Query",
+        "description": "Object not found",
+        "issue_codes": [1029],
+    },
+    "GENERIC_DB_ENGINE_ERROR": {
+        "category": "General",
+        "description": "Database engine error",
+        "issue_codes": [1002],
+    },
+}
+
+
+def extract_string_from_call(node: ast.Call) -> str | None:
+    """Extract string from __() or _() translation calls."""
+    if not node.args:
+        return None
+    arg = node.args[0]
+    if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
+        return arg.value
+    elif isinstance(arg, ast.JoinedStr):
+        # f-string - try to reconstruct
+        parts = []
+        for value in arg.values:
+            if isinstance(value, ast.Constant):
+                parts.append(str(value.value))
+            elif isinstance(value, ast.FormattedValue):
+                # Just use a placeholder
+                parts.append("{...}")
+        return "".join(parts)
+    return None
+
+
+def extract_custom_errors_from_file(filepath: Path) -> dict[str, 
list[dict[str, Any]]]:
+    """
+    Extract custom_errors definitions from a Python engine spec file.
+
+    Returns a dict mapping class names to their custom errors list.
+    """
+    results = {}
+
+    try:
+        with open(filepath, "r", encoding="utf-8") as f:
+            source = f.read()
+
+        tree = ast.parse(source)
+
+        for node in ast.walk(tree):
+            if isinstance(node, ast.ClassDef):
+                class_name = node.name
+
+                for item in node.body:
+                    # Look for custom_errors = { ... }
+                    if (
+                        isinstance(item, ast.AnnAssign)
+                        and isinstance(item.target, ast.Name)
+                        and item.target.id == "custom_errors"
+                        and isinstance(item.value, ast.Dict)
+                    ):
+                        errors = extract_errors_from_dict(item.value, source)
+                        if errors:
+                            results[class_name] = errors
+
+                    # Also handle simple assignment: custom_errors = { ... }
+                    elif (
+                        isinstance(item, ast.Assign)
+                        and len(item.targets) == 1
+                        and isinstance(item.targets[0], ast.Name)
+                        and item.targets[0].id == "custom_errors"
+                        and isinstance(item.value, ast.Dict)
+                    ):
+                        errors = extract_errors_from_dict(item.value, source)
+                        if errors:
+                            results[class_name] = errors
+
+    except (OSError, SyntaxError, ValueError) as e:
+        print(f"Error parsing {filepath}: {e}", file=sys.stderr)
+
+    return results
+
+
+def extract_regex_info(key: ast.expr) -> dict[str, Any]:
+    """Extract regex pattern info from the dict key."""
+    if isinstance(key, ast.Name):
+        return {"regex_name": key.id}
+    if isinstance(key, ast.Call):
+        if (
+            isinstance(key.func, ast.Attribute)
+            and key.func.attr == "compile"
+            and key.args
+            and isinstance(key.args[0], ast.Constant)
+        ):
+            return {"regex_pattern": key.args[0].value}
+    return {}
+
+
+def extract_invalid_fields(extra_node: ast.Dict) -> list[str]:
+    """Extract invalid fields from the extra dict."""
+    for k, v in zip(extra_node.keys, extra_node.values, strict=False):
+        if (
+            isinstance(k, ast.Constant)
+            and k.value == "invalid"
+            and isinstance(v, ast.List)
+        ):
+            return [elem.value for elem in v.elts if isinstance(elem, 
ast.Constant)]
+    return []
+
+
+def extract_error_tuple_info(value: ast.Tuple) -> dict[str, Any]:
+    """Extract error info from the (message, error_type, extra) tuple."""
+    result: dict[str, Any] = {}
+
+    # First element: message template
+    msg_node = value.elts[0]
+    if isinstance(msg_node, ast.Call):
+        message = extract_string_from_call(msg_node)
+        if message:
+            result["message_template"] = message
+    elif isinstance(msg_node, ast.Constant):
+        result["message_template"] = msg_node.value
+
+    # Second element: SupersetErrorType.SOMETHING
+    type_node = value.elts[1]
+    if isinstance(type_node, ast.Attribute):
+        error_type = type_node.attr
+        result["error_type"] = error_type
+        if error_type in ERROR_TYPE_INFO:
+            type_info = ERROR_TYPE_INFO[error_type]
+            result["category"] = type_info["category"]
+            result["description"] = type_info["description"]
+            result["issue_codes"] = type_info["issue_codes"]
+
+    # Third element: extra dict with invalid fields
+    if len(value.elts) >= 3 and isinstance(value.elts[2], ast.Dict):
+        invalid_fields = extract_invalid_fields(value.elts[2])
+        if invalid_fields:
+            result["invalid_fields"] = invalid_fields
+
+    return result
+
+
+def extract_errors_from_dict(dict_node: ast.Dict, source: str) -> 
list[dict[str, Any]]:
+    """Extract error information from a custom_errors dict AST node."""
+    errors = []
+
+    for key, value in zip(dict_node.keys, dict_node.values, strict=False):
+        if key is None or value is None:
+            continue
+
+        error_info = extract_regex_info(key)
+
+        if isinstance(value, ast.Tuple) and len(value.elts) >= 2:
+            error_info.update(extract_error_tuple_info(value))
+
+        if error_info.get("error_type") and error_info.get("message_template"):
+            errors.append(error_info)
+
+    return errors
+
+
+def main() -> None:
+    """Main function to extract custom_errors from all engine specs."""
+    # Find the superset root directory
+    script_dir = Path(__file__).parent
+    root_dir = script_dir.parent.parent
+    specs_dir = root_dir / "superset" / "db_engine_specs"
+
+    if not specs_dir.exists():
+        print(f"Error: Engine specs directory not found: {specs_dir}", 
file=sys.stderr)
+        sys.exit(1)
+
+    all_errors = {}
+
+    # Process each Python file in the specs directory
+    for filepath in sorted(specs_dir.glob("*.py")):
+        if filepath.name.startswith("_"):
+            continue
+
+        module_name = filepath.stem
+        class_errors = extract_custom_errors_from_file(filepath)
+
+        if class_errors:
+            # Store errors by module and class
+            all_errors[module_name] = class_errors
+
+    # Output as JSON
+    print(json.dumps(all_errors, indent=2))
+
+
+if __name__ == "__main__":
+    main()
diff --git a/docs/scripts/generate-database-docs.mjs 
b/docs/scripts/generate-database-docs.mjs
index cde02d127d..04980f24f8 100644
--- a/docs/scripts/generate-database-docs.mjs
+++ b/docs/scripts/generate-database-docs.mjs
@@ -675,6 +675,78 @@ function updateReadme(databases) {
   return false;
 }
 
+/**
+ * Extract custom_errors from engine specs for troubleshooting documentation
+ * Returns a map of module names to their custom errors
+ */
+function extractCustomErrors() {
+  console.log('Extracting custom_errors from engine specs...');
+
+  try {
+    const scriptPath = path.join(__dirname, 'extract_custom_errors.py');
+    const result = spawnSync('python3', [scriptPath], {
+      cwd: ROOT_DIR,
+      encoding: 'utf-8',
+      timeout: 30000,
+      maxBuffer: 10 * 1024 * 1024,
+    });
+
+    if (result.error) {
+      throw result.error;
+    }
+    if (result.status !== 0) {
+      throw new Error(result.stderr || 'Python script failed');
+    }
+
+    const customErrors = JSON.parse(result.stdout);
+    const moduleCount = Object.keys(customErrors).length;
+    const errorCount = Object.values(customErrors).reduce((sum, classes) =>
+      sum + Object.values(classes).reduce((s, errs) => s + errs.length, 0), 0);
+    console.log(`  Found ${errorCount} custom errors across ${moduleCount} 
modules`);
+    return customErrors;
+  } catch (err) {
+    console.log('  Could not extract custom_errors:', err.message);
+    return null;
+  }
+}
+
+/**
+ * Merge custom_errors into database documentation
+ * Maps by module name since that's how both datasets are keyed
+ */
+function mergeCustomErrors(databases, customErrors) {
+  if (!customErrors) return;
+
+  let mergedCount = 0;
+
+  for (const [, db] of Object.entries(databases)) {
+    if (!db.module) continue;
+    // Normalize module name: Flask mode uses full path 
(superset.db_engine_specs.postgres),
+    // but customErrors is keyed by file stem (postgres)
+    const moduleName = db.module.split('.').pop();
+    if (!customErrors[moduleName]) continue;
+
+    // Get all errors from all classes in this module
+    const moduleErrors = customErrors[moduleName];
+    const allErrors = [];
+
+    for (const classErrors of Object.values(moduleErrors)) {
+      allErrors.push(...classErrors);
+    }
+
+    if (allErrors.length > 0) {
+      // Add to documentation
+      db.documentation = db.documentation || {};
+      db.documentation.custom_errors = allErrors;
+      mergedCount++;
+    }
+  }
+
+  if (mergedCount > 0) {
+    console.log(`  Merged custom_errors into ${mergedCount} database docs`);
+  }
+}
+
 /**
  * Load existing database data if available
  */
@@ -768,6 +840,10 @@ async function main() {
     databases = mergeWithExistingDiagnostics(databases, existingData);
   }
 
+  // Extract and merge custom_errors for troubleshooting documentation
+  const customErrors = extractCustomErrors();
+  mergeCustomErrors(databases, customErrors);
+
   // Build statistics
   const statistics = buildStatistics(databases);
 
diff --git a/docs/src/components/databases/DatabaseIndex.tsx 
b/docs/src/components/databases/DatabaseIndex.tsx
index 89eee4782d..fee4f1a36b 100644
--- a/docs/src/components/databases/DatabaseIndex.tsx
+++ b/docs/src/components/databases/DatabaseIndex.tsx
@@ -26,6 +26,7 @@ import {
   KeyOutlined,
   SearchOutlined,
   LinkOutlined,
+  BugOutlined,
 } from '@ant-design/icons';
 import type { DatabaseData, DatabaseInfo, TimeGrains } from './types';
 
@@ -44,6 +45,8 @@ interface TableEntry {
   hasDrivers: boolean;
   hasAuthMethods: boolean;
   hasConnectionString: boolean;
+  hasCustomErrors: boolean;
+  customErrorCount: number;
   joins?: boolean;
   subqueries?: boolean;
   supports_dynamic_schema?: boolean;
@@ -223,6 +226,8 @@ const DatabaseIndex: React.FC<DatabaseIndexProps> = ({ data 
}) => {
           db.documentation?.connection_string ||
             (db.documentation?.drivers?.length ?? 0) > 0
         ),
+        hasCustomErrors: (db.documentation?.custom_errors?.length ?? 0) > 0,
+        customErrorCount: db.documentation?.custom_errors?.length ?? 0,
         isCompatible: false,
       });
 
@@ -246,6 +251,8 @@ const DatabaseIndex: React.FC<DatabaseIndexProps> = ({ data 
}) => {
             hasDrivers: false,
             hasAuthMethods: false,
             hasConnectionString: Boolean(compat.connection_string),
+            hasCustomErrors: false,
+            customErrorCount: 0,
             joins: db.joins,
             subqueries: db.subqueries,
             supports_dynamic_schema: db.supports_dynamic_schema,
@@ -457,7 +464,7 @@ const DatabaseIndex: React.FC<DatabaseIndexProps> = ({ data 
}) => {
     {
       title: 'Documentation',
       key: 'docs',
-      width: 150,
+      width: 180,
       render: (_: unknown, record: TableEntry) => (
         <div style={{ display: 'flex', gap: '4px', flexWrap: 'wrap' }}>
           {record.hasConnectionString && (
@@ -475,6 +482,13 @@ const DatabaseIndex: React.FC<DatabaseIndexProps> = ({ 
data }) => {
               Auth
             </Tag>
           )}
+          {record.hasCustomErrors && (
+            <Tooltip title={`${record.customErrorCount} troubleshooting tips`}>
+              <Tag icon={<BugOutlined />} color="volcano">
+                Errors
+              </Tag>
+            </Tooltip>
+          )}
         </div>
       ),
     },
diff --git a/docs/src/components/databases/DatabasePage.tsx 
b/docs/src/components/databases/DatabasePage.tsx
index 836680b746..c02d4a44a1 100644
--- a/docs/src/components/databases/DatabasePage.tsx
+++ b/docs/src/components/databases/DatabasePage.tsx
@@ -39,6 +39,7 @@ import {
   BookOutlined,
   EditOutlined,
   GithubOutlined,
+  BugOutlined,
 } from '@ant-design/icons';
 import type { DatabaseInfo } from './types';
 
@@ -414,6 +415,132 @@ const DatabasePage: React.FC<DatabasePageProps> = ({ 
database, name }) => {
     );
   };
 
+  // Render troubleshooting / custom errors section
+  const renderTroubleshooting = () => {
+    if (!docs?.custom_errors?.length) return null;
+
+    // Group errors by category
+    const errorsByCategory: Record<string, typeof docs.custom_errors> = {};
+    for (const error of docs.custom_errors) {
+      const category = error.category || 'General';
+      if (!errorsByCategory[category]) {
+        errorsByCategory[category] = [];
+      }
+      errorsByCategory[category].push(error);
+    }
+
+    // Define category order for consistent display
+    const categoryOrder = [
+      'Authentication',
+      'Connection',
+      'Permissions',
+      'Query',
+      'Configuration',
+      'General',
+    ];
+
+    const sortedCategories = Object.keys(errorsByCategory).sort((a, b) => {
+      const aIdx = categoryOrder.indexOf(a);
+      const bIdx = categoryOrder.indexOf(b);
+      if (aIdx === -1 && bIdx === -1) return a.localeCompare(b);
+      if (aIdx === -1) return 1;
+      if (bIdx === -1) return -1;
+      return aIdx - bIdx;
+    });
+
+    // Category colors
+    const categoryColors: Record<string, string> = {
+      Authentication: 'orange',
+      Connection: 'red',
+      Permissions: 'purple',
+      Query: 'blue',
+      Configuration: 'cyan',
+      General: 'default',
+    };
+
+    return (
+      <Card
+        title={
+          <>
+            <BugOutlined /> Troubleshooting
+          </>
+        }
+        style={{ marginBottom: 16 }}
+      >
+        <Paragraph type="secondary">
+          Common error messages you may encounter when connecting to or 
querying{' '}
+          {name}, along with their causes and solutions.
+        </Paragraph>
+        <Collapse accordion>
+          {sortedCategories.map((category) => (
+            <Panel
+              header={
+                <span>
+                  <Tag color={categoryColors[category] || 'default'}>
+                    {category}
+                  </Tag>
+                  {errorsByCategory[category].length} error
+                  {errorsByCategory[category].length !== 1 ? 's' : ''}
+                </span>
+              }
+              key={category}
+            >
+              {errorsByCategory[category].map((error, idx) => (
+                <div
+                  key={idx}
+                  style={{
+                    marginBottom:
+                      idx < errorsByCategory[category].length - 1 ? 16 : 0,
+                    paddingBottom:
+                      idx < errorsByCategory[category].length - 1 ? 16 : 0,
+                    borderBottom:
+                      idx < errorsByCategory[category].length - 1
+                        ? '1px solid var(--ifm-color-emphasis-200)'
+                        : 'none',
+                  }}
+                >
+                  <div style={{ marginBottom: 8 }}>
+                    <Text strong>{error.description || error.error_type}</Text>
+                  </div>
+                  <Alert
+                    message={error.message_template}
+                    type="error"
+                    style={{ marginBottom: 8 }}
+                  />
+                  {error.invalid_fields && error.invalid_fields.length > 0 && (
+                    <div style={{ marginBottom: 8 }}>
+                      <Text type="secondary">Check these fields: </Text>
+                      {error.invalid_fields.map((field) => (
+                        <Tag key={field} color="warning">
+                          {field}
+                        </Tag>
+                      ))}
+                    </div>
+                  )}
+                  {error.issue_codes && error.issue_codes.length > 0 && (
+                    <div>
+                      <Text type="secondary">Related issue codes: </Text>
+                      {error.issue_codes.map((code) => (
+                        <Tag key={code}>
+                          <a
+                            
href={`/docs/using-superset/issue-codes#issue-${code}`}
+                            style={{ color: 'inherit' }}
+                          >
+                            Issue {code}
+                          </a>
+                        </Tag>
+                      ))}
+                    </div>
+                  )}
+                </div>
+              ))}
+            </Panel>
+          ))}
+        </Collapse>
+      </Card>
+    );
+  };
+
   return (
     <div
       className="database-page"
@@ -556,6 +683,9 @@ const DatabasePage: React.FC<DatabasePageProps> = ({ 
database, name }) => {
       {/* Time Grains */}
       {renderTimeGrains()}
 
+      {/* Troubleshooting / Custom Errors */}
+      {renderTroubleshooting()}
+
       {/* Compatible Databases */}
       {renderCompatibleDatabases()}
 
diff --git a/docs/src/components/databases/types.ts 
b/docs/src/components/databases/types.ts
index 698c93e2cc..d1ad59e74b 100644
--- a/docs/src/components/databases/types.ts
+++ b/docs/src/components/databases/types.ts
@@ -86,6 +86,17 @@ export interface CompatibleDatabase {
   docs_url?: string;
 }
 
+export interface CustomError {
+  error_type: string;           // e.g., "CONNECTION_INVALID_USERNAME_ERROR"
+  message_template: string;     // e.g., 'The username "%(username)s" does not 
exist.'
+  regex_pattern?: string;       // The regex pattern that matches this error 
(optional, for reference)
+  regex_name?: string;          // The name of the regex constant (e.g., 
"CONNECTION_INVALID_USERNAME_REGEX")
+  invalid_fields?: string[];    // Fields that are invalid, e.g., ["username", 
"password"]
+  issue_codes?: number[];       // Related issue codes from ISSUE_CODES mapping
+  category?: string;            // Error category: "Authentication", 
"Connection", "Query", etc.
+  description?: string;         // Human-readable short description of the 
error type
+}
+
 export interface DatabaseDocumentation {
   description?: string;
   logo?: string;
@@ -111,6 +122,7 @@ export interface DatabaseDocumentation {
   sqlalchemy_docs_url?: string;
   advanced_features?: Record<string, string>;
   compatible_databases?: CompatibleDatabase[];
+  custom_errors?: CustomError[];  // Database-specific error messages and 
troubleshooting info
 }
 
 export interface TimeGrains {
diff --git a/docs/src/data/databases.json b/docs/src/data/databases.json
index 35e91f79a9..0605694146 100644
--- a/docs/src/data/databases.json
+++ b/docs/src/data/databases.json
@@ -1,5 +1,5 @@
 {
-  "generated": "2026-01-21T21:46:41.044Z",
+  "generated": "2026-01-21T23:22:58.314Z",
   "statistics": {
     "totalDatabases": 67,
     "withDocumentation": 67,
@@ -333,7 +333,19 @@
             }
           }
         ],
-        "notes": "URL-encode special characters in s3_staging_dir (e.g., s3:// 
becomes s3%3A//)."
+        "notes": "URL-encode special characters in s3_staging_dir (e.g., s3:// 
becomes s3%3A//).",
+        "custom_errors": [
+          {
+            "regex_name": "SYNTAX_ERROR_REGEX",
+            "message_template": "Please check your query for syntax errors at 
or near \"%(syntax_error)s\". Then, try running your query again.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          }
+        ]
       },
       "time_grains": {},
       "score": 0,
@@ -516,7 +528,62 @@
         "warnings": [
           "Google BigQuery Python SDK is not compatible with gevent. Use a 
worker type other than gevent when deploying with gunicorn."
         ],
-        "docs_url": "https://github.com/googleapis/python-bigquery-sqlalchemy";
+        "docs_url": "https://github.com/googleapis/python-bigquery-sqlalchemy";,
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_DATABASE_PERMISSIONS_REGEX",
+            "message_template": "Unable to connect. Verify that the following 
roles are set on the service account: \"BigQuery Data Viewer\", \"BigQuery 
Metadata Viewer\", \"BigQuery Job User\" and the following permissions are set 
\"bigquery.readsessions.create\", \"bigquery.readsessions.getData\"",
+            "error_type": "CONNECTION_DATABASE_PERMISSIONS_ERROR",
+            "category": "Permissions",
+            "description": "Insufficient permissions",
+            "issue_codes": [
+              1017
+            ]
+          },
+          {
+            "regex_name": "TABLE_DOES_NOT_EXIST_REGEX",
+            "message_template": "The table \"%(table)s\" does not exist. A 
valid table must be used to run this query.",
+            "error_type": "TABLE_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Table not found",
+            "issue_codes": [
+              1003,
+              1005
+            ]
+          },
+          {
+            "regex_name": "COLUMN_DOES_NOT_EXIST_REGEX",
+            "message_template": "We can't seem to resolve column 
\"%(column)s\" at line %(location)s.",
+            "error_type": "COLUMN_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Column not found",
+            "issue_codes": [
+              1003,
+              1004
+            ]
+          },
+          {
+            "regex_name": "SCHEMA_DOES_NOT_EXIST_REGEX",
+            "message_template": "The schema \"%(schema)s\" does not exist. A 
valid schema must be used to run this query.",
+            "error_type": "SCHEMA_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Schema not found",
+            "issue_codes": [
+              1003,
+              1016
+            ]
+          },
+          {
+            "regex_name": "SYNTAX_ERROR_REGEX",
+            "message_template": "Please check your query for syntax errors at 
or near \"%(syntax_error)s\". Then, try running your query again.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          }
+        ]
       },
       "time_grains": {},
       "score": 0,
@@ -1214,6 +1281,120 @@
             "is_recommended": true,
             "notes": "Uses PostgreSQL wire protocol."
           }
+        ],
+        "custom_errors": [
+          {
+            "message_template": "Incorrect username or password.",
+            "error_type": "CONNECTION_INVALID_USERNAME_ERROR",
+            "category": "Authentication",
+            "description": "Invalid username",
+            "issue_codes": [
+              1012
+            ],
+            "invalid_fields": [
+              "username",
+              "password"
+            ]
+          },
+          {
+            "message_template": "Please enter a password.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ],
+            "invalid_fields": [
+              "password"
+            ]
+          },
+          {
+            "message_template": "Hostname \"%(hostname)s\" cannot be 
resolved.",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ],
+            "invalid_fields": [
+              "host"
+            ]
+          },
+          {
+            "message_template": "Server refused the connection: check hostname 
and port.",
+            "error_type": "CONNECTION_PORT_CLOSED_ERROR",
+            "category": "Connection",
+            "description": "Port closed or refused",
+            "issue_codes": [
+              1008
+            ],
+            "invalid_fields": [
+              "host",
+              "port"
+            ]
+          },
+          {
+            "message_template": "Unable to connect to database 
\"%(database)s\"",
+            "error_type": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "category": "Connection",
+            "description": "Unknown database",
+            "issue_codes": [
+              1015
+            ],
+            "invalid_fields": [
+              "database"
+            ]
+          },
+          {
+            "message_template": "Unable to connect to database 
\"%(database)s\": database does not exist or insufficient permissions",
+            "error_type": "CONNECTION_DATABASE_PERMISSIONS_ERROR",
+            "category": "Permissions",
+            "description": "Insufficient permissions",
+            "issue_codes": [
+              1017
+            ],
+            "invalid_fields": [
+              "database"
+            ]
+          },
+          {
+            "message_template": "Please check your query for syntax errors at 
or near \"%(err)s\". Then, try running your query again.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          },
+          {
+            "message_template": "Column \"%(column)s\" not found in 
\"%(view)s\".",
+            "error_type": "COLUMN_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Column not found",
+            "issue_codes": [
+              1003,
+              1004
+            ]
+          },
+          {
+            "message_template": "Invalid aggregation expression.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          },
+          {
+            "message_template": "\"%(exp)s\" is neither an aggregation 
function nor appears in the GROUP BY clause.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          }
         ]
       },
       "time_grains": {
@@ -1313,6 +1494,73 @@
           "APACHE_PROJECTS",
           "ANALYTICAL_DATABASES",
           "OPEN_SOURCE"
+        ],
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_ACCESS_DENIED_REGEX",
+            "message_template": "Either the username \"%(username)s\" or the 
password is incorrect.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ],
+            "invalid_fields": [
+              "username",
+              "password"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_HOSTNAME_REGEX",
+            "message_template": "Unknown Doris server host \"%(hostname)s\".",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ],
+            "invalid_fields": [
+              "host"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_HOST_DOWN_REGEX",
+            "message_template": "The host \"%(hostname)s\" might be down and 
can't be reached.",
+            "error_type": "CONNECTION_HOST_DOWN_ERROR",
+            "category": "Connection",
+            "description": "Host unreachable",
+            "issue_codes": [
+              1009
+            ],
+            "invalid_fields": [
+              "host",
+              "port"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_UNKNOWN_DATABASE_REGEX",
+            "message_template": "Unable to connect to database 
\"%(database)s\".",
+            "error_type": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "category": "Connection",
+            "description": "Unknown database",
+            "issue_codes": [
+              1015
+            ],
+            "invalid_fields": [
+              "database"
+            ]
+          },
+          {
+            "regex_name": "SYNTAX_ERROR_REGEX",
+            "message_template": "Please check your query for syntax errors 
near \"%(server_error)s\". Then, try running your query again.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          }
         ]
       },
       "time_grains": {
@@ -1650,6 +1898,19 @@
               "HOSTED_OPEN_SOURCE"
             ]
           }
+        ],
+        "custom_errors": [
+          {
+            "regex_name": "COLUMN_DOES_NOT_EXIST_REGEX",
+            "message_template": "We can't seem to resolve the column 
\"%(column_name)s\"",
+            "error_type": "COLUMN_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Column not found",
+            "issue_codes": [
+              1003,
+              1004
+            ]
+          }
         ]
       },
       "time_grains": {
@@ -1727,7 +1988,20 @@
           "database": "MotherDuck database name",
           "token": "Service token from MotherDuck dashboard"
         },
-        "docs_url": "https://motherduck.com/docs/getting-started/";
+        "docs_url": "https://motherduck.com/docs/getting-started/";,
+        "custom_errors": [
+          {
+            "regex_name": "COLUMN_DOES_NOT_EXIST_REGEX",
+            "message_template": "We can't seem to resolve the column 
\"%(column_name)s\"",
+            "error_type": "COLUMN_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Column not found",
+            "issue_codes": [
+              1003,
+              1004
+            ]
+          }
+        ]
       },
       "time_grains": {},
       "score": 0,
@@ -2159,7 +2433,19 @@
           "CLOUD_GCP",
           "HOSTED_OPEN_SOURCE"
         ],
-        "install_instructions": "pip install \"apache-superset[gsheets]\""
+        "install_instructions": "pip install \"apache-superset[gsheets]\"",
+        "custom_errors": [
+          {
+            "regex_name": "SYNTAX_ERROR_REGEX",
+            "message_template": "Please check your query for syntax errors 
near \"%(server_error)s\". Then, try running your query again.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          }
+        ]
       },
       "time_grains": {
         "SECOND": true,
@@ -2755,7 +3041,50 @@
             "notes": "Connection string must be URL-encoded. Special 
characters like @ need encoding."
           }
         ],
-        "docs_url": 
"https://docs.sqlalchemy.org/en/20/core/engines.html#escaping-special-characters-such-as-signs-in-passwords";
+        "docs_url": 
"https://docs.sqlalchemy.org/en/20/core/engines.html#escaping-special-characters-such-as-signs-in-passwords";,
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_ACCESS_DENIED_REGEX",
+            "message_template": "Either the username \"%(username)s\", 
password, or database name \"%(database)s\" is incorrect.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_HOSTNAME_REGEX",
+            "message_template": "The hostname \"%(hostname)s\" cannot be 
resolved.",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_PORT_CLOSED_REGEX",
+            "message_template": "Port %(port)s on hostname \"%(hostname)s\" 
refused the connection.",
+            "error_type": "CONNECTION_PORT_CLOSED_ERROR",
+            "category": "Connection",
+            "description": "Port closed or refused",
+            "issue_codes": [
+              1008
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_HOST_DOWN_REGEX",
+            "message_template": "The host \"%(hostname)s\" might be down, and 
can't be reached on port %(port)s.",
+            "error_type": "CONNECTION_HOST_DOWN_ERROR",
+            "category": "Connection",
+            "description": "Host unreachable",
+            "issue_codes": [
+              1009
+            ]
+          }
+        ]
       },
       "time_grains": {
         "SECOND": true,
@@ -2828,6 +3157,49 @@
           "CLOUD_DATA_WAREHOUSES",
           "ANALYTICAL_DATABASES",
           "PROPRIETARY"
+        ],
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_ACCESS_DENIED_REGEX",
+            "message_template": "Either the username \"%(username)s\", 
password, or database name \"%(database)s\" is incorrect.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_HOSTNAME_REGEX",
+            "message_template": "The hostname \"%(hostname)s\" cannot be 
resolved.",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_PORT_CLOSED_REGEX",
+            "message_template": "Port %(port)s on hostname \"%(hostname)s\" 
refused the connection.",
+            "error_type": "CONNECTION_PORT_CLOSED_ERROR",
+            "category": "Connection",
+            "description": "Port closed or refused",
+            "issue_codes": [
+              1008
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_HOST_DOWN_REGEX",
+            "message_template": "The host \"%(hostname)s\" might be down, and 
can't be reached on port %(port)s.",
+            "error_type": "CONNECTION_HOST_DOWN_ERROR",
+            "category": "Connection",
+            "description": "Host unreachable",
+            "issue_codes": [
+              1009
+            ]
+          }
         ]
       },
       "time_grains": {},
@@ -2939,6 +3311,73 @@
               "HOSTED_OPEN_SOURCE"
             ]
           }
+        ],
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_ACCESS_DENIED_REGEX",
+            "message_template": "Either the username \"%(username)s\" or the 
password is incorrect.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ],
+            "invalid_fields": [
+              "username",
+              "password"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_HOSTNAME_REGEX",
+            "message_template": "Unknown MySQL server host \"%(hostname)s\".",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ],
+            "invalid_fields": [
+              "host"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_HOST_DOWN_REGEX",
+            "message_template": "The host \"%(hostname)s\" might be down and 
can't be reached.",
+            "error_type": "CONNECTION_HOST_DOWN_ERROR",
+            "category": "Connection",
+            "description": "Host unreachable",
+            "issue_codes": [
+              1009
+            ],
+            "invalid_fields": [
+              "host",
+              "port"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_UNKNOWN_DATABASE_REGEX",
+            "message_template": "Unable to connect to database 
\"%(database)s\".",
+            "error_type": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "category": "Connection",
+            "description": "Unknown database",
+            "issue_codes": [
+              1015
+            ],
+            "invalid_fields": [
+              "database"
+            ]
+          },
+          {
+            "regex_name": "SYNTAX_ERROR_REGEX",
+            "message_template": "Please check your query for syntax errors 
near \"%(server_error)s\". Then, try running your query again.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          }
         ]
       },
       "time_grains": {
@@ -3068,6 +3507,73 @@
         "categories": [
           "TRADITIONAL_RDBMS",
           "OPEN_SOURCE"
+        ],
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_ACCESS_DENIED_REGEX",
+            "message_template": "Either the username \"%(username)s\" or the 
password is incorrect.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ],
+            "invalid_fields": [
+              "username",
+              "password"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_HOSTNAME_REGEX",
+            "message_template": "Unknown OceanBase server host 
\"%(hostname)s\".",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ],
+            "invalid_fields": [
+              "host"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_HOST_DOWN_REGEX",
+            "message_template": "The host \"%(hostname)s\" might be down and 
can't be reached.",
+            "error_type": "CONNECTION_HOST_DOWN_ERROR",
+            "category": "Connection",
+            "description": "Host unreachable",
+            "issue_codes": [
+              1009
+            ],
+            "invalid_fields": [
+              "host",
+              "port"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_UNKNOWN_DATABASE_REGEX",
+            "message_template": "Unable to connect to database 
\"%(database)s\".",
+            "error_type": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "category": "Connection",
+            "description": "Unknown database",
+            "issue_codes": [
+              1015
+            ],
+            "invalid_fields": [
+              "database"
+            ]
+          },
+          {
+            "regex_name": "SYNTAX_ERROR_REGEX",
+            "message_template": "Please check your query for syntax errors 
near \"%(server_error)s\". Then, try running your query again.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          }
         ]
       },
       "time_grains": {},
@@ -3099,7 +3605,96 @@
           "sqlalchemy-ocient"
         ],
         "connection_string": 
"ocient://{username}:{password}@{host}:{port}/{database}",
-        "install_instructions": "pip install sqlalchemy-ocient"
+        "install_instructions": "pip install sqlalchemy-ocient",
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_INVALID_USERNAME_REGEX",
+            "message_template": "The username \"%(username)s\" does not 
exist.",
+            "error_type": "CONNECTION_INVALID_USERNAME_ERROR",
+            "category": "Authentication",
+            "description": "Invalid username",
+            "issue_codes": [
+              1012
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_PASSWORD_REGEX",
+            "message_template": "The user/password combination is not valid 
(Incorrect password for user).",
+            "error_type": "CONNECTION_INVALID_PASSWORD_ERROR",
+            "category": "Authentication",
+            "description": "Invalid password",
+            "issue_codes": [
+              1013
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_UNKNOWN_DATABASE_REGEX",
+            "message_template": "Could not connect to database: 
\"%(database)s\"",
+            "error_type": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "category": "Connection",
+            "description": "Unknown database",
+            "issue_codes": [
+              1015
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_HOSTNAME_REGEX",
+            "message_template": "Could not resolve hostname: \"%(host)s\".",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_PORT_ERROR",
+            "message_template": "Port out of range 0-65535",
+            "error_type": "CONNECTION_INVALID_PORT_ERROR"
+          },
+          {
+            "regex_name": "INVALID_CONNECTION_STRING_REGEX",
+            "message_template": "Invalid Connection String: Expecting String 
of the form 'ocient://user:pass@host:port/database'.",
+            "error_type": "GENERIC_DB_ENGINE_ERROR",
+            "category": "General",
+            "description": "Database engine error",
+            "issue_codes": [
+              1002
+            ]
+          },
+          {
+            "regex_name": "SYNTAX_ERROR_REGEX",
+            "message_template": "Syntax Error: %(qualifier)s input 
\"%(input)s\" expecting \"%(expected)s",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          },
+          {
+            "regex_name": "TABLE_DOES_NOT_EXIST_REGEX",
+            "message_template": "Table or View \"%(table)s\" does not exist.",
+            "error_type": "TABLE_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Table not found",
+            "issue_codes": [
+              1003,
+              1005
+            ]
+          },
+          {
+            "regex_name": "COLUMN_DOES_NOT_EXIST_REGEX",
+            "message_template": "Invalid reference to column: \"%(column)s\"",
+            "error_type": "COLUMN_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Column not found",
+            "issue_codes": [
+              1003,
+              1004
+            ]
+          }
+        ]
       },
       "time_grains": {
         "SECOND": true,
@@ -3446,6 +4041,124 @@
               "HOSTED_OPEN_SOURCE"
             ]
           }
+        ],
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_INVALID_USERNAME_REGEX",
+            "message_template": "The username \"%(username)s\" does not 
exist.",
+            "error_type": "CONNECTION_INVALID_USERNAME_ERROR",
+            "category": "Authentication",
+            "description": "Invalid username",
+            "issue_codes": [
+              1012
+            ],
+            "invalid_fields": [
+              "username"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_PASSWORD_REGEX",
+            "message_template": "The password provided for username 
\"%(username)s\" is incorrect.",
+            "error_type": "CONNECTION_INVALID_PASSWORD_ERROR",
+            "category": "Authentication",
+            "description": "Invalid password",
+            "issue_codes": [
+              1013
+            ],
+            "invalid_fields": [
+              "username",
+              "password"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_PASSWORD_NEEDED_REGEX",
+            "message_template": "Please re-enter the password.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ],
+            "invalid_fields": [
+              "password"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_HOSTNAME_REGEX",
+            "message_template": "The hostname \"%(hostname)s\" cannot be 
resolved.",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ],
+            "invalid_fields": [
+              "host"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_PORT_CLOSED_REGEX",
+            "message_template": "Port %(port)s on hostname \"%(hostname)s\" 
refused the connection.",
+            "error_type": "CONNECTION_PORT_CLOSED_ERROR",
+            "category": "Connection",
+            "description": "Port closed or refused",
+            "issue_codes": [
+              1008
+            ],
+            "invalid_fields": [
+              "host",
+              "port"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_HOST_DOWN_REGEX",
+            "message_template": "The host \"%(hostname)s\" might be down, and 
can't be reached on port %(port)s.",
+            "error_type": "CONNECTION_HOST_DOWN_ERROR",
+            "category": "Connection",
+            "description": "Host unreachable",
+            "issue_codes": [
+              1009
+            ],
+            "invalid_fields": [
+              "host",
+              "port"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_UNKNOWN_DATABASE_REGEX",
+            "message_template": "Unable to connect to database 
\"%(database)s\".",
+            "error_type": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "category": "Connection",
+            "description": "Unknown database",
+            "issue_codes": [
+              1015
+            ],
+            "invalid_fields": [
+              "database"
+            ]
+          },
+          {
+            "regex_name": "COLUMN_DOES_NOT_EXIST_REGEX",
+            "message_template": "We can't seem to resolve the column 
\"%(column_name)s\" at line %(location)s.",
+            "error_type": "COLUMN_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Column not found",
+            "issue_codes": [
+              1003,
+              1004
+            ]
+          },
+          {
+            "regex_name": "SYNTAX_ERROR_REGEX",
+            "message_template": "Please check your query for syntax errors at 
or near \"%(syntax_error)s\". Then, try running your query again.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          }
         ]
       },
       "time_grains": {
@@ -3515,6 +4228,92 @@
             "connection_string": "presto://{hostname}:{port}/{database}",
             "is_recommended": true
           }
+        ],
+        "custom_errors": [
+          {
+            "regex_name": "COLUMN_DOES_NOT_EXIST_REGEX",
+            "message_template": "We can't seem to resolve the column 
\"%(column_name)s\" at line %(location)s.",
+            "error_type": "COLUMN_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Column not found",
+            "issue_codes": [
+              1003,
+              1004
+            ]
+          },
+          {
+            "regex_name": "TABLE_DOES_NOT_EXIST_REGEX",
+            "message_template": "The table \"%(table_name)s\" does not exist. 
A valid table must be used to run this query.",
+            "error_type": "TABLE_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Table not found",
+            "issue_codes": [
+              1003,
+              1005
+            ]
+          },
+          {
+            "regex_name": "SCHEMA_DOES_NOT_EXIST_REGEX",
+            "message_template": "The schema \"%(schema_name)s\" does not 
exist. A valid schema must be used to run this query.",
+            "error_type": "SCHEMA_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Schema not found",
+            "issue_codes": [
+              1003,
+              1016
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_ACCESS_DENIED_REGEX",
+            "message_template": "Either the username \"%(username)s\" or the 
password is incorrect.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_HOSTNAME_REGEX",
+            "message_template": "The hostname \"%(hostname)s\" cannot be 
resolved.",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_HOST_DOWN_REGEX",
+            "message_template": "The host \"%(hostname)s\" might be down, and 
can't be reached on port %(port)s.",
+            "error_type": "CONNECTION_HOST_DOWN_ERROR",
+            "category": "Connection",
+            "description": "Host unreachable",
+            "issue_codes": [
+              1009
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_PORT_CLOSED_REGEX",
+            "message_template": "Port %(port)s on hostname \"%(hostname)s\" 
refused the connection.",
+            "error_type": "CONNECTION_PORT_CLOSED_ERROR",
+            "category": "Connection",
+            "description": "Port closed or refused",
+            "issue_codes": [
+              1008
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "message_template": "Unable to connect to catalog named 
\"%(catalog_name)s\".",
+            "error_type": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "category": "Connection",
+            "description": "Unknown database",
+            "issue_codes": [
+              1015
+            ]
+          }
         ]
       },
       "time_grains": {
@@ -3625,6 +4424,77 @@
               }
             }
           }
+        ],
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_ACCESS_DENIED_REGEX",
+            "message_template": "Either the username \"%(username)s\" or the 
password is incorrect.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ],
+            "invalid_fields": [
+              "username",
+              "password"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_INVALID_HOSTNAME_REGEX",
+            "message_template": "The hostname \"%(hostname)s\" cannot be 
resolved.",
+            "error_type": "CONNECTION_INVALID_HOSTNAME_ERROR",
+            "category": "Connection",
+            "description": "Invalid hostname",
+            "issue_codes": [
+              1007
+            ],
+            "invalid_fields": [
+              "host"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_PORT_CLOSED_REGEX",
+            "message_template": "Port %(port)s on hostname \"%(hostname)s\" 
refused the connection.",
+            "error_type": "CONNECTION_PORT_CLOSED_ERROR",
+            "category": "Connection",
+            "description": "Port closed or refused",
+            "issue_codes": [
+              1008
+            ],
+            "invalid_fields": [
+              "host",
+              "port"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_HOST_DOWN_REGEX",
+            "message_template": "The host \"%(hostname)s\" might be down, and 
can't be reached on port %(port)s.",
+            "error_type": "CONNECTION_HOST_DOWN_ERROR",
+            "category": "Connection",
+            "description": "Host unreachable",
+            "issue_codes": [
+              1009
+            ],
+            "invalid_fields": [
+              "host",
+              "port"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_UNKNOWN_DATABASE_REGEX",
+            "message_template": "We were unable to connect to your database 
named \"%(database)s\". Please verify your database name and try again.",
+            "error_type": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "category": "Connection",
+            "description": "Unknown database",
+            "issue_codes": [
+              1015
+            ],
+            "invalid_fields": [
+              "database"
+            ]
+          }
         ]
       },
       "time_grains": {},
@@ -3858,7 +4728,29 @@
           }
         ],
         "notes": "Schema is not required in connection string. Ensure user has 
privileges for all databases/schemas/tables/views/warehouses.",
-        "docs_url": 
"https://docs.snowflake.com/en/user-guide/key-pair-auth.html";
+        "docs_url": 
"https://docs.snowflake.com/en/user-guide/key-pair-auth.html";,
+        "custom_errors": [
+          {
+            "regex_name": "OBJECT_DOES_NOT_EXIST_REGEX",
+            "message_template": "%(object)s does not exist in this database.",
+            "error_type": "OBJECT_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Object not found",
+            "issue_codes": [
+              1029
+            ]
+          },
+          {
+            "regex_name": "SYNTAX_ERROR_REGEX",
+            "message_template": "Please check your query for syntax errors at 
or near \"%(syntax_error)s\". Then, try running your query again.",
+            "error_type": "SYNTAX_ERROR",
+            "category": "Query",
+            "description": "SQL syntax error",
+            "issue_codes": [
+              1030
+            ]
+          }
+        ]
       },
       "time_grains": {
         "SECOND": true,
@@ -4039,7 +4931,20 @@
         ],
         "pypi_packages": [],
         "connection_string": 
"sqlite:///path/to/file.db?check_same_thread=false",
-        "notes": "No additional library needed. SQLite is bundled with Python."
+        "notes": "No additional library needed. SQLite is bundled with 
Python.",
+        "custom_errors": [
+          {
+            "regex_name": "COLUMN_DOES_NOT_EXIST_REGEX",
+            "message_template": "We can't seem to resolve the column 
\"%(column_name)s\"",
+            "error_type": "COLUMN_DOES_NOT_EXIST_ERROR",
+            "category": "Query",
+            "description": "Column not found",
+            "issue_codes": [
+              1003,
+              1004
+            ]
+          }
+        ]
       },
       "time_grains": {
         "SECOND": true,
@@ -4183,6 +5088,36 @@
             },
             "docs_url": "https://docs.celerdata.com/";
           }
+        ],
+        "custom_errors": [
+          {
+            "regex_name": "CONNECTION_ACCESS_DENIED_REGEX",
+            "message_template": "Either the username \"%(username)s\" or the 
password is incorrect.",
+            "error_type": "CONNECTION_ACCESS_DENIED_ERROR",
+            "category": "Authentication",
+            "description": "Access denied",
+            "issue_codes": [
+              1014,
+              1015
+            ],
+            "invalid_fields": [
+              "username",
+              "password"
+            ]
+          },
+          {
+            "regex_name": "CONNECTION_UNKNOWN_DATABASE_REGEX",
+            "message_template": "Unable to connect to database 
\"%(database)s\".",
+            "error_type": "CONNECTION_UNKNOWN_DATABASE_ERROR",
+            "category": "Connection",
+            "description": "Unknown database",
+            "issue_codes": [
+              1015
+            ],
+            "invalid_fields": [
+              "database"
+            ]
+          }
         ]
       },
       "time_grains": {

Reply via email to