apache / superset

Apache Superset is a Data Visualization and Data Exploration Platform
https://superset.apache.org/
Apache License 2.0
62.45k stars 13.73k forks source link

Dashboard Import Error Shows HTML Code #30584

Open OldrichDlouhy opened 2 weeks ago

OldrichDlouhy commented 2 weeks ago

Bug description

When importing dashboard and the import fails, the error displayed is leaking HTML code of error page.

It seems there is other exception thrown when the import exception is processed.

Screenshots/recordings

image

Superset version

4.0.2

Python version

3.9

Node version

16

Browser

Chrome

Additional context

Extracted stacktrace from the displayed message:

Traceback (most recent call last): 
        File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1823, in full_dispatch_request rv = self.dispatch_request() 
        File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1799, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) 
        File "/usr/local/lib/python3.10/site-packages/flask_appbuilder/security/decorators.py", line 95, in wraps return f(self, *args, **kwargs) 
        File "/app/superset/views/base_api.py", line 127, in wraps raise ex File "/app/superset/views/base_api.py", line 121, in wraps duration, response = time_function(f, self, *args, **kwargs) 
        File "/app/superset/utils/core.py", line 1470, in time_function response = func(*args, **kwargs) 
        File "/app/superset/utils/log.py", line 255, in wrapper value = f(*args, **kwargs) 
        File "/app/superset/views/base_api.py", line 108, in wraps return f(self, *args, **kwargs) 
        File "/app/superset/dashboards/api.py", line 1135, in import_ command.run() 
        File "/app/superset/commands/dashboard/importers/dispatcher.py", line 64, in run raise exc 
        File "/app/superset/commands/dashboard/importers/dispatcher.py", line 57, in run command.run() 
        File "/app/superset/commands/importers/v1/__init__.py", line 71, in run self.validate() 
        File "/app/superset/commands/importers/v1/__init__.py", line 109, in validate raise CommandInvalidError( superset.commands.exceptions.CommandInvalidError: Error importing dashboard During handling of the above exception, another exception occurred:

        Traceback (most recent call last): 
        File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 2529, in wsgi_app response = self.full_dispatch_request() 
        File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1825, in full_dispatch_request rv = self.handle_user_exception(e) 
        File "/usr/local/lib/python3.10/site-packages/flask_cors/extension.py", line 165, in wrapped_function return cors_after_request(app.make_response(f(*args, **kwargs))) 
        File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1676, in handle_user_exception return self.ensure_sync(handler)(e)
        File "/app/superset/views/base.py", line 505, in show_command_errors return json_errors_response( 
        File "/app/superset/views/base.py", line 165, in json_errors_response payload["errors"] = [dataclasses.asdict(error) for error in errors]
        File "/app/superset/views/base.py", line 165, in <listcomp> payload["errors"] = [dataclasses.asdict(error) for error in errors] 
        File "/usr/local/lib/python3.10/dataclasses.py", line 1238, in asdict return _asdict_inner(obj, dict_factory) 
        File "/usr/local/lib/python3.10/dataclasses.py", line 1245, in _asdict_inner value = _asdict_inner(getattr(obj, f.name), dict_factory) 
        File "/usr/local/lib/python3.10/dataclasses.py", line 1275, in _asdict_inner return type(obj)((_asdict_inner(k, dict_factory), 
        File "/usr/local/lib/python3.10/dataclasses.py", line 1276, in <genexpr> _asdict_inner(v, dict_factory)) 
        File "/usr/local/lib/python3.10/dataclasses.py", line 1275, in _asdict_inner return type(obj)((_asdict_inner(k, dict_factory), 
        File "/usr/local/lib/python3.10/dataclasses.py", line 1276, in <genexpr> _asdict_inner(v, dict_factory)) 
        File "/usr/local/lib/python3.10/dataclasses.py", line 1275, in _asdict_inner return type(obj)((_asdict_inner(k, dict_factory), 
        File "/usr/local/lib/python3.10/dataclasses.py", line 1276, in <genexpr> _asdict_inner(v, dict_factory)) 
        File "/usr/local/lib/python3.10/dataclasses.py", line 1275, in _asdict_inner return type(obj)((_asdict_inner(k, dict_factory), TypeError: first argument must be callable or None 

Checklist

dosubot[bot] commented 2 weeks ago

Hello, @OldrichDlouhy! I'm here to help you with your bug report. If you need assistance with anything else, feel free to ask.

I found a similar issue related to a "500 - Internal Server Error" during dashboard import, which was caused by a CommandInvalidError. The solution involves ensuring proper error handling and mapping the error to a SupersetErrorException or SupersetErrorsException with a specific status code and error type.

To address the HTML code leakage and improve error handling:

  1. Validation: Ensure the metadata and configurations are correct. The validate method in ImportAssetsCommand checks these and raises CommandInvalidError if there are issues.

  2. Error Handling: Use the error handler for CommandException to log the error and return a JSON error response. If the error is a CommandInvalidError, include additional normalized messages in the response.

Here's a snippet for handling the error:

@app.errorhandler(CommandException)
def show_command_errors(ex: CommandException) -> FlaskResponse:
    logger.warning("CommandException", exc_info=True)
    if "text/html" in request.accept_mimetypes and not app.config["DEBUG"]:
        path = files("superset") / "static/assets/500.html"
        return send_file(path, max_age=0), 500

    extra = ex.normalized_messages() if isinstance(ex, CommandInvalidError) else {}
    return json_error_response(
        [
            SupersetError(
                message=ex.message,
                error_type=SupersetErrorType.GENERIC_COMMAND_ERROR,
                level=get_error_level_from_status(ex.status),
                extra=extra,
            ),
        ],
        status=ex.status,
    )

Ensure this handler is set up in your Flask app to catch and process CommandInvalidError exceptions, providing a more informative error response [1][2].

To continue talking to Dosu, mention @dosu.

remcoboerma commented 4 days ago

Had a similar issue using superset on Yunohost. This helpmed troubleshoot the error for me.

index f90708acf5..2fd0579a0f 100644
--- a/superset/commands/importers/v1/__init__.py
+++ b/superset/commands/importers/v1/__init__.py
@@ -104,6 +104,8 @@ class ImportModelsCommand(BaseCommand):
         self._prevent_overwrite_existing_model(exceptions)

         if exceptions:
+            import sys
+            print('NEEDLE',exceptions,file=sys.stderr)
             raise CommandInvalidError(
                 f"Error importing {self.model_name}",
                 exceptions,

Printing the exceptions that are otherwise invislble allowed me to see what was causing the import error (invalid data in the exported yaml file). As stderr is routed towards the service output it's viewable in the logs in yunohost.

It's not a solution, but solved my most urgend problem. Hope it helps someone else.