Repository: plotly/dash
File: dash/_callback.py (Python)

Code before:
                    error = output_value.get("long_callback_error")
                    raise LongCallbackError(
                        f"An error occurred inside a long callback: {error['msg']}\n{error['tb']}"
                    )

                if job_running and output_value is not callback_manager.UNDEFINED:
                    # cached results.
                    callback_manager.terminate_job(job_id)

                if multi and isinstance(output_value, (list, tuple)):
                    output_value = [
                        NoUpdate() if NoUpdate.is_no_update(r) else r
                        for r in output_value
                    ]
                updated_props = callback_manager.get_updated_props(cache_key)
                if len(updated_props) > 0:
                    response["sideUpdate"] = updated_props
                    has_update = True

                if output_value is callback_manager.UNDEFINED:
                    return to_json(response)
            else:
                try:
                    output_value = _invoke_callback(func, *func_args, **func_kwargs)
                except Exception as err:  # pylint: disable=broad-exception-caught
                    if on_error:
                        output_value = on_error(err)
                    elif app_on_error:
                        output_value = app_on_error(err)
                    else:
                        raise err

            if NoUpdate.is_no_update(output_value):
                raise PreventUpdate

            component_ids = collections.defaultdict(dict)

            if has_output:
                if not multi:
                    output_value, output_spec = [output_value], [output_spec]
                    flat_output_values = output_value
                else:
                    if isinstance(output_value, (list, tuple)):
                        # For multi-output, allow top-level collection to be
                        # list or tuple
                        output_value = list(output_value)

                    # Flatten grouping and validate grouping structure
                    flat_output_values = flatten_grouping(output_value, output)

                _validate.validate_multi_return(

Review comment (suggestion):
Why not do something like `on_error_func = on_error or app_on_error` further up in the code, to avoid this extra `elif`

Code after:
                    # Job canceled -> no output to close the loop.
                    output_value = NoUpdate()

                elif (
                    isinstance(output_value, dict)
                    and "long_callback_error" in output_value
                ):
                    error = output_value.get("long_callback_error", {})
                    exc = LongCallbackError(
                        f"An error occurred inside a long callback: {error['msg']}\n{error['tb']}"
                    )
                    if error_handler:
                        output_value = error_handler(exc)

                        if output_value is None:
                            output_value = NoUpdate()
                        # set_props from the error handler uses the original ctx
                        # instead of manager.get_updated_props since it runs in the
                        # request process.
                        has_update = (
                            _set_side_update(callback_ctx, response)
                            or output_value is not None
                        )
                    else:
                        raise exc

                if job_running and output_value is not callback_manager.UNDEFINED:
                    # cached results.
                    callback_manager.terminate_job(job_id)

                if multi and isinstance(output_value, (list, tuple)):
                    output_value = [
                        NoUpdate() if NoUpdate.is_no_update(r) else r
                        for r in output_value
                    ]
                updated_props = callback_manager.get_updated_props(cache_key)
                if len(updated_props) > 0:
                    response["sideUpdate"] = updated_props
                    has_update = True

                if output_value is callback_manager.UNDEFINED:
                    return to_json(response)
            else:
                try:
                    output_value = _invoke_callback(func, *func_args, **func_kwargs)
                except PreventUpdate as err:
                    raise err
                except Exception as err:  # pylint: disable=broad-exception-caught
                    if error_handler:
                        output_value = error_handler(err)