Skip to content

Make Exeption traceable in lazy listener #635

Description

@jimmymaise

(Describe your issue and goal here)
Currently, using lazy listener for FAAS (such as AWS Lambda), it's really difficult to debug. If we have a exception, we just have something like

Failed to run an internal function (Exception ABC)

We don't know exactly, what is the error, traceback, error line etc...

 try:
            await internal_func(
                **build_async_required_kwargs(
                    logger=logger,
                    required_arg_names=arg_names,
                    request=request,
                    response=None,
                    this_func=internal_func,
                )
            )
        except Exception as e:
            logger.error(f"Failed to run an internal function ({e})")

So should we have an option to enable the exception traceback or provide some meaningful error information to debug instead of just simply message like that

On the other hand, the document about error handling does not work with lazy listener so we also need to update.
https://slack.dev/bolt-python/concepts#errors

Category (place an x in each of the [ ])

  • slack_bolt.App and/or its core components
  • slack_bolt.async_app.AsyncApp and/or its core components
  • Adapters in slack_bolt.adapter
  • [x ] Others

Requirements

Please read the Contributing guidelines and Code of Conduct before creating this issue or pull request. By submitting, you are agreeing to those rules.

Activity

  1. changed the title [-]Make Exeption traceable in lazy listion[/-] [+]Make Exeption traceable in lazy listener[/+] on Apr 20, 2022
  2. added this to the 1.x milestone on Apr 20, 2022
  3. self-assigned this
    on Apr 20, 2022
  4. seratch commented on Apr 20, 2022

    @seratch
    Contributor

    Hi @jimmymaise, thanks for the feedback. We will look into this. This can be improved in future versions and/or needs to be clearly mentioned in the documents.

  5. ddhanak commented on Aug 18, 2022

    @ddhanak

    We are facing the same issue as @jimmymaise, I think it would be helpful to have the exception traceback (we are using sentry and would love to see what line is causing the issue).

  6. kevgliss commented on Jan 10, 2023

    @kevgliss

    We are also facing this issue; it's often unclear what is causing an exception (or swallowing them entirely).

  7. angrychimp commented on Sep 11, 2023

    @angrychimp
    Contributor

    I'm running into this issue frequently as well. I'd love to see this updated

  8. os1ma commented on Apr 20, 2024

    @os1ma

    I'm running into the same issue.

    As a workaround, I was able to display the stack trace with the following code.

    from concurrent.futures import Executor
    from functools import wraps
    from logging import Logger
    from typing import Callable
    
    from slack_bolt.kwargs_injection import build_required_kwargs
    from slack_bolt.lazy_listener.runner import LazyListenerRunner
    from slack_bolt.request import BoltRequest
    from slack_bolt.util.utils import get_arg_names_of_callable
    
    
    def build_runnable_function(
        func: Callable[..., None],
        logger: Logger,
        request: BoltRequest,
    ) -> Callable[[], None]:
        arg_names = get_arg_names_of_callable(func)
    
        @wraps(func)
        def request_wired_func_wrapper() -> None:
            try:
                func(
                    **build_required_kwargs(
                        logger=logger,
                        required_arg_names=arg_names,
                        request=request,
                        response=None,
                        this_func=func,
                    )
                )
            except Exception as e:
    -            logger.error(f"Failed to run an internal function ({e})")
    +            logger.exception(f"Failed to run an internal function ({e})")
    
        return request_wired_func_wrapper
    
    
    class PatchedThreadLazyListenerRunner(LazyListenerRunner):
        logger: Logger
    
        def __init__(
            self,
            logger: Logger,
            executor: Executor,
        ):
            self.logger = logger
            self.executor = executor
    
        def start(self, function: Callable[..., None], request: BoltRequest) -> None:
            self.executor.submit(
                build_runnable_function(
                    func=function,
                    logger=self.logger,
                    request=request,
                )
            )
    app.listener_runner.lazy_listener_runner = PatchedThreadLazyListenerRunner(
        logger=app._framework_logger,
        executor=app.listener_runner.listener_executor,
    )

    However, this is a hacky workaround that strongly depends on the internal structure of this framework, so it's not desirable. I would be happy if bolt framework would resolve this issue.

  9. johnorcutt commented on Mar 27, 2025

    @johnorcutt

    We've been running into this issue as well. Has there been any progress on this issue?

  10. thentges commented on Jan 15, 2026

    @thentges

    Just stumbled across this issue as well, found a workaround by decorating the functions I use as lazy listeners but would love to see it included in base package 👍

  11. luqmansen commented on May 5, 2026

    @luqmansen

    Just stumbled upon the same issue, and I think the fix is quite simple by wrapping the lazy received with try-catch, no?

    def process_message(body: dict, client: "WebClient") -> None:
        try:
            my_dispatch(body, client)
        except Exception:
            logger.exception("process_message failed")
            raise
    
    bolt_app.event("message")(ack=lambda ack: ack(), lazy=[process_message])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions