blob: 02f420794211b7961ea56c073006bb3f76f162da [file] [log] [blame]
# 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.
# pylint: disable=too-few-public-methods,invalid-name
from dataclasses import dataclass # pylint: disable=wrong-import-order
from enum import Enum
from typing import Any, Dict, Optional
from flask_babel import gettext as _
class SupersetErrorType(str, Enum):
"""
Types of errors that can exist within Superset.
Keep in sync with superset-frontend/src/components/ErrorMessage/types.ts
and docs/src/pages/docs/Miscellaneous/issue_codes.mdx
"""
# Frontend errors
FRONTEND_CSRF_ERROR = "FRONTEND_CSRF_ERROR"
FRONTEND_NETWORK_ERROR = "FRONTEND_NETWORK_ERROR"
FRONTEND_TIMEOUT_ERROR = "FRONTEND_TIMEOUT_ERROR"
# DB Engine errors
GENERIC_DB_ENGINE_ERROR = "GENERIC_DB_ENGINE_ERROR"
COLUMN_DOES_NOT_EXIST_ERROR = "COLUMN_DOES_NOT_EXIST_ERROR"
TABLE_DOES_NOT_EXIST_ERROR = "TABLE_DOES_NOT_EXIST_ERROR"
SCHEMA_DOES_NOT_EXIST_ERROR = "SCHEMA_DOES_NOT_EXIST_ERROR"
CONNECTION_INVALID_USERNAME_ERROR = "CONNECTION_INVALID_USERNAME_ERROR"
CONNECTION_INVALID_PASSWORD_ERROR = "CONNECTION_INVALID_PASSWORD_ERROR"
CONNECTION_INVALID_HOSTNAME_ERROR = "CONNECTION_INVALID_HOSTNAME_ERROR"
CONNECTION_PORT_CLOSED_ERROR = "CONNECTION_PORT_CLOSED_ERROR"
CONNECTION_HOST_DOWN_ERROR = "CONNECTION_HOST_DOWN_ERROR"
CONNECTION_ACCESS_DENIED_ERROR = "CONNECTION_ACCESS_DENIED_ERROR"
CONNECTION_UNKNOWN_DATABASE_ERROR = "CONNECTION_UNKNOWN_DATABASE_ERROR"
CONNECTION_DATABASE_PERMISSIONS_ERROR = "CONNECTION_DATABASE_PERMISSIONS_ERROR"
CONNECTION_MISSING_PARAMETERS_ERROR = "CONNECTION_MISSING_PARAMETERS_ERROR"
# Viz errors
VIZ_GET_DF_ERROR = "VIZ_GET_DF_ERROR"
UNKNOWN_DATASOURCE_TYPE_ERROR = "UNKNOWN_DATASOURCE_TYPE_ERROR"
FAILED_FETCHING_DATASOURCE_INFO_ERROR = "FAILED_FETCHING_DATASOURCE_INFO_ERROR"
# Security access errors
TABLE_SECURITY_ACCESS_ERROR = "TABLE_SECURITY_ACCESS_ERROR"
DATASOURCE_SECURITY_ACCESS_ERROR = "DATASOURCE_SECURITY_ACCESS_ERROR"
DATABASE_SECURITY_ACCESS_ERROR = "DATABASE_SECURITY_ACCESS_ERROR"
MISSING_OWNERSHIP_ERROR = "MISSING_OWNERSHIP_ERROR"
# Other errors
BACKEND_TIMEOUT_ERROR = "BACKEND_TIMEOUT_ERROR"
# Sql Lab errors
MISSING_TEMPLATE_PARAMS_ERROR = "MISSING_TEMPLATE_PARAMS_ERROR"
RESULTS_BACKEND_NOT_CONFIGURED_ERROR = "RESULTS_BACKEND_NOT_CONFIGURED_ERROR"
DML_NOT_ALLOWED_ERROR = "DML_NOT_ALLOWED_ERROR"
INVALID_CTAS_QUERY_ERROR = "INVALID_CTAS_QUERY_ERROR"
INVALID_CVAS_QUERY_ERROR = "INVALID_CVAS_QUERY_ERROR"
SQLLAB_TIMEOUT_ERROR = "SQLLAB_TIMEOUT_ERROR"
# Generic errors
GENERIC_COMMAND_ERROR = "GENERIC_COMMAND_ERROR"
GENERIC_BACKEND_ERROR = "GENERIC_BACKEND_ERROR"
# API errors
INVALID_PAYLOAD_FORMAT_ERROR = "INVALID_PAYLOAD_FORMAT_ERROR"
INVALID_PAYLOAD_SCHEMA_ERROR = "INVALID_PAYLOAD_SCHEMA_ERROR"
ERROR_TYPES_TO_ISSUE_CODES_MAPPING = {
SupersetErrorType.BACKEND_TIMEOUT_ERROR: [
{
"code": 1000,
"message": _("Issue 1000 - The datasource is too large to query."),
},
{
"code": 1001,
"message": _("Issue 1001 - The database is under an unusual load."),
},
],
SupersetErrorType.GENERIC_DB_ENGINE_ERROR: [
{
"code": 1002,
"message": _("Issue 1002 - The database returned an unexpected error."),
}
],
SupersetErrorType.COLUMN_DOES_NOT_EXIST_ERROR: [
{
"code": 1003,
"message": _(
"Issue 1003 - There is a syntax error in the SQL query. "
"Perhaps there was a misspelling or a typo."
),
},
{
"code": 1004,
"message": _(
"Issue 1004 - The column was deleted or renamed in the database."
),
},
],
SupersetErrorType.TABLE_DOES_NOT_EXIST_ERROR: [
{
"code": 1003,
"message": _(
"Issue 1003 - There is a syntax error in the SQL query. "
"Perhaps there was a misspelling or a typo."
),
},
{
"code": 1005,
"message": _(
"Issue 1005 - The table was deleted or renamed in the database."
),
},
],
SupersetErrorType.SCHEMA_DOES_NOT_EXIST_ERROR: [
{
"code": 1003,
"message": _(
"Issue 1003 - There is a syntax error in the SQL query. "
"Perhaps there was a misspelling or a typo."
),
},
{
"code": 1016,
"message": _(
"Issue 1005 - The schema was deleted or renamed in the database."
),
},
],
SupersetErrorType.MISSING_TEMPLATE_PARAMS_ERROR: [
{
"code": 1006,
"message": _(
"Issue 1006 - One or more parameters specified in the query are "
"missing."
),
},
],
SupersetErrorType.RESULTS_BACKEND_NOT_CONFIGURED_ERROR: [
{
"code": 1021,
"message": _(
"Issue 1021 - Results backend needed for asynchronous queries "
"is not configured."
),
},
],
SupersetErrorType.DML_NOT_ALLOWED_ERROR: [
{
"code": 1022,
"message": _("Issue 1022 - Database does not allow data manipulation."),
},
],
SupersetErrorType.CONNECTION_INVALID_HOSTNAME_ERROR: [
{
"code": 1007,
"message": _("Issue 1007 - The hostname provided can't be resolved."),
},
],
SupersetErrorType.CONNECTION_PORT_CLOSED_ERROR: [
{"code": 1008, "message": _("Issue 1008 - The port is closed.")},
],
SupersetErrorType.CONNECTION_HOST_DOWN_ERROR: [
{
"code": 1009,
"message": _(
"Issue 1009 - The host might be down, and can't be reached on the "
"provided port."
),
},
],
SupersetErrorType.GENERIC_COMMAND_ERROR: [
{
"code": 1010,
"message": _(
"Issue 1010 - Superset encountered an error while running a command."
),
},
],
SupersetErrorType.GENERIC_BACKEND_ERROR: [
{
"code": 1011,
"message": _("Issue 1011 - Superset encountered an unexpected error."),
},
],
SupersetErrorType.CONNECTION_INVALID_USERNAME_ERROR: [
{
"code": 1012,
"message": _(
"Issue 1012 - The username provided when "
"connecting to a database is not valid."
),
},
],
SupersetErrorType.CONNECTION_INVALID_PASSWORD_ERROR: [
{
"code": 1013,
"message": _(
"Issue 1013 - The password provided when "
"connecting to a database is not valid."
),
},
],
SupersetErrorType.CONNECTION_ACCESS_DENIED_ERROR: [
{
"code": 1014,
"message": _("Issue 1014 - Either the username or the password is wrong."),
},
{
"code": 1015,
"message": _(
"Issue 1015 - Either the database is "
"spelled incorrectly or does not exist."
),
},
],
SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR: [
{
"code": 1015,
"message": _(
"Issue 1015 - Either the database is "
"spelled incorrectly or does not exist."
),
}
],
SupersetErrorType.CONNECTION_DATABASE_PERMISSIONS_ERROR: [
{
"code": 1017,
"message": _("Issue 1017 - User doesn't have the proper permissions."),
},
],
SupersetErrorType.CONNECTION_MISSING_PARAMETERS_ERROR: [
{
"code": 1018,
"message": _(
"Issue 1018 - One or more parameters needed to configure a "
"database are missing."
),
},
],
SupersetErrorType.INVALID_PAYLOAD_FORMAT_ERROR: [
{
"code": 1019,
"message": _(
"Issue 1019 - The submitted payload has the incorrect format."
),
}
],
SupersetErrorType.INVALID_PAYLOAD_SCHEMA_ERROR: [
{
"code": 1020,
"message": _(
"Issue 1020 - The submitted payload has the incorrect schema."
),
}
],
SupersetErrorType.INVALID_CTAS_QUERY_ERROR: [
{
"code": 1023,
"message": _(
"Issue 1023 - The CTAS (create table as select) doesn't have a "
"SELECT statement at the end. Please make sure your query has a "
"SELECT as its last statement. Then, try running your query again."
),
},
],
SupersetErrorType.INVALID_CVAS_QUERY_ERROR: [
{
"code": 1024,
"message": _(
"Issue 1024 - CVAS (create view as select) query has more than "
"one statement."
),
},
{
"code": 1025,
"message": _(
"Issue 1025 - CVAS (create view as select) query is not a "
"SELECT statement."
),
},
],
SupersetErrorType.SQLLAB_TIMEOUT_ERROR: [
{
"code": 1026,
"message": _(
"Issue 1026 - Query is too complex and takes too long to run."
),
},
{
"code": 1027,
"message": _(
"Issue 1027 - The database is currently running too many queries."
),
},
],
}
class ErrorLevel(str, Enum):
"""
Levels of errors that can exist within Superset.
Keep in sync with superset-frontend/src/components/ErrorMessage/types.ts
"""
INFO = "info"
WARNING = "warning"
ERROR = "error"
@dataclass
class SupersetError:
"""
An error that is returned to a client.
"""
message: str
error_type: SupersetErrorType
level: ErrorLevel
extra: Optional[Dict[str, Any]] = None
def __post_init__(self) -> None:
"""
Mutates the extra params with user facing error codes that map to backend
errors.
"""
issue_codes = ERROR_TYPES_TO_ISSUE_CODES_MAPPING.get(self.error_type)
if issue_codes:
self.extra = self.extra or {}
self.extra.update({"issue_codes": issue_codes})