hotwired / hotwired/stimulus

Exceptions in async controller action not caught by stimulus

Open
#730 2 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
13.1k
Forks
441
PR merge metrics
No merged PRs in 30d

Description

Stimulus doesn't catch exceptions thrown from async controller actions. This means that

a) We don't get nice stimulus errors in the console
b) handleError is never called, so overriding it (e.g. to log errors to a monitoring system like Sentry or Azure App Insights) has no effect.

This happens because the call to user code (this.method.call(this.controller, actionEvent)) is not awaited, so it returns a Promise immediately, and escapes the try catch block.

https://github.com/hotwired/stimulus/blob/5fd12c7b6af88620741e3aa969b6ab440559c5b7/src/core/binding.ts#L74-L84

I think something like this would work:

  invokeWithEvent(event) {
    function handleError(error) {
      const { identifier, controller, element, index } = this;
      const detail = { identifier, controller, element, index, event };
      this.context.handleError(error, `invoking action "${this.action}"`, detail);
    }

    const { target, currentTarget } = event;
    try {
      const { params } = this.action;
      const actionEvent = Object.assign(event, { params });
      Promise.resolve(this.method.call(this.controller, actionEvent)).catch(error => handleError(error));
      this.context.logDebugActivity(this.methodName, { event, target, currentTarget, action: this.methodName });
    } catch (error) {
      handleError(error);
    }
  }

I think this is really important, because without the ability to configure custom error handling that applies to all stimulus controller code, users running production apps wont have visibility into how their async actions are failing, without putting a try catch block into every one of those methods.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read src/core/binding.ts around the linked invokeWithEvent implementation, focusing on how the controller method is invoked and how errors reach handleError. Verify the behavior for both synchronous and asynchronous exceptions, and confirm that async failures produce the expected console error and invoke custom error handling.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.