Skip to content

fix: implement proper error handling. #1115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 24, 2025
Merged

Conversation

Hweinstock
Copy link
Contributor

@Hweinstock Hweinstock commented Apr 24, 2025

Problem

Error handling for backend requests is non-existent and the existing error handling elsewhere relies on flaky checks.

Testing these changes with @jpinkney-aws, we identified 3 problems fixed by these changes.

  • backend errors cause chat to hang.
  • the stop button doesn't always stop the action depending on the time it was pressed.
  • the authenticate button doesn't pop-up, its blocked by "thinking...".

Solution

  • forward backend error message to the client to be displayed in chat.
  • on error, send a progress update to the client to kill the thinking bubble.
  • centralize error handling to minimize flaky checks.

Testing

  • In addition to unit tests, these changes were tested e2e. See demo below for a demonstration where I have the model always fail on the second iteration of the agentic loop.
errorHandlingFix.mov

Notes

there is a hack implemented to ensure the thinking bubble is killed. This highlights potential bugs in the chat-client and is explained with a comment in the code.

Future Work

  • Investigate the best way to propagate the error to the user. (potentially using ResponseError and handling it on client side).
  • Determine how we want to format the error since not all Q api responses should be shown to customer.

License

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@Hweinstock Hweinstock marked this pull request as ready for review April 24, 2025 13:42
@Hweinstock Hweinstock requested a review from a team as a code owner April 24, 2025 13:42
@Hweinstock Hweinstock marked this pull request as draft April 24, 2025 13:42
@Hweinstock Hweinstock changed the title refactor: centralize userAction error handling fix: implement proper error handling. Apr 24, 2025
@Hweinstock Hweinstock marked this pull request as ready for review April 24, 2025 18:23
Copy link
Contributor

@jpinkney-aws jpinkney-aws left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving after the last change

@Hweinstock Hweinstock merged commit 4a7bfdc into aws:main Apr 24, 2025
6 checks passed
@Hweinstock Hweinstock deleted the userActionError branch April 24, 2025 19:26
)
const backendError = err.cause
// Send the backend error message directly to the client to be displayed in chat.
return {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another, more LSP, way to handle this would be to return ResponseError in result of LSP request. Then extension would need to translate that to error on the UI by calling "errorMessage" command with params through postMessage.

Copy link
Contributor Author

@Hweinstock Hweinstock Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that makes sense. My thinking was that if we wanted any custom formatting on this message in the future it could be done once on the LSP side rather than reimplemented by each client. Is there a way to do that using ResponseError?

Looks like this can be done by passing in a ChatResult as data in the error potentially?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ResponseError has generic data param, so that might be used. Custom formatting could also be on chat-client side (here), depending on what exactly you mean.

return response
} catch (e) {
this.#features.logging.error(`Error in call: ${JSON.stringify(e)}`)
throw new ModelServiceException(e as Error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, we also throw throw new Error('amazonQServiceManager is not initialized') from within generateAssistantResponse (aka makeRequest) function. Which is something that should not be show to user.

Additionally, is exception thrown from Q API user-friendly enough to show it to user?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were asking the same question. We reached out the backend team and they said this should be okay for now, but we'll likely want something better in the long run.

I was hoping to find a better solution here, but wasn't able to given the time constraints.

jpinkney-aws pushed a commit that referenced this pull request Apr 25, 2025
## Problem
- Some follow up work from #1115. 

## Solution
- Follow the LSP paradigm to return response error to the client, and handle it there. 
- This is in combination with client side changes [here](aws/aws-toolkit-vscode#7161). 
- These together produce the following experience on model api failures.
this.#debug(`cause ${err instanceof Error ? JSON.stringify(err.cause) : 'unknown'}`)
return new ResponseError<ChatResult>(
LSPErrorCodes.RequestFailed,
err instanceof Error ? err.message : 'Unknown request error'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any plans to add something like innerCode which holds the code (sdk v2) or name (sdk v3) from the original error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it sounds like their isn't yet a reliable way to distinguish errors produced by the backend yet (source). So rather than rely on their errors, I refactored this to wrap their error and include a code field , but only on the language server side, and is not sent back to the client.

My intention with this error handling is to do as much on the language server side as possible, such that the client will only have to render the ChatResult from the data field of the ResponseError. My thinking is that this will reduce the amount of custom error handling each IDE will have to implement.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes. But for unforeseen cases, we might want to give clients an escape-hatch? Else they will need to do their own checks, or check the message text, for errors that require client-side handling (such as #1197 )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants