Skip to content
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

Add OasstError exception class and corresponding exception filter #120

Merged
merged 4 commits into from
Dec 28, 2022

Conversation

andreaskoepf
Copy link
Collaborator

@andreaskoepf andreaskoepf commented Dec 28, 2022

This PR introduces the exception class OasstError that can always be used to signal a backend error to the API client with message and open-assistant error_code. It should not be used when the message could leak security relevant information. OasstError is 'picklable'.

The ctor of OasstError takes parameters message: str, error_code: int, http_status_code: int = HTTP_400_BAD_REQUEST. The error-code is a numeric reference to the specific error-site in the backend.

An exception handler is registered which generates a json response with message and error_code (using a http-status code as specified by the OasstError class).

Resolves #55

@andreaskoepf andreaskoepf marked this pull request as ready for review December 28, 2022 13:21
Copy link
Collaborator

@yk yk left a comment

Choose a reason for hiding this comment

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

LGTM, left just small comments


@app.exception_handler(OasstError)
async def oasst_exception_handler(request: fastapi.Request, ex: OasstError):
logger.error(f"{request.method} {request.url} failed: {repr(ex)}")
Copy link
Collaborator

Choose a reason for hiding this comment

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

loguru also has logger.exception that gives a nice trace of the exception (in the current context) and annotates all parameters with their values, it's really nice to debug, but also very verbose, maybe worth thinking about

Copy link
Collaborator Author

@andreaskoepf andreaskoepf Dec 28, 2022

Choose a reason for hiding this comment

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

Yes, I had exactly that first but removed it again: For OasstErrors it is clear where they come from, e.g. they are usually post translation of generic internal errors. We could think about referencing 'inner exceptions' in the class that could be forwarded to the client when a server debug setting is True.

I was also looking into general handlers for uncaught Exceptions. IMO it would make sense to remove the general except Exception handlers and do the translation into 500 Internal Server Error centralized .. there logger.exception() would definitely make sense.

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
Open-Assistant backend API error codes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

suggestion: make these into an IntEnum, so they're still int, but typing could be used

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Had that too initially. Also the question could be int vs. string error codes .. in general I had good experience with these site-level error codes .. it is a bit work during development but if a user sends you such a code you instantly can track where it came from (even without exposing stack-traces etc.)...

Copy link
Collaborator

@yk yk Dec 28, 2022

Choose a reason for hiding this comment

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

yes I don't think any of that would change with an IntEnum. it would just be nicer to instead of having to take an int parameter, be able to take an OAsstErrorCode parameter (that behaves like an int)

Copy link
Collaborator Author

@andreaskoepf andreaskoepf Dec 28, 2022

Choose a reason for hiding this comment

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

(regarding typing .. I normally put such an exception class in a shared lib, the error_code param has type int to prevent dependencies between the base exception class and each and every error_code that would be defined in dependent libs). It would make sense to derive 'local' exception classes from it .. but I am not sure if the exception-filter type check in fast-api is polymorphic. I will try that.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have now used a simple IntEnum for the error codes.

Important: There was an error in api_auth(), probably introduced when DEBUG_SKIP_API_KEY_CHECK was added,
see

api_client = db.query(ApiClient).filter(ApiClient.api_key == api_key).first()
if api_client is not None and api_client.enabled:
return api_client
... if the DB query returned None the function returned None (instead of raising an Unauthorized error...)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

To clarify: the api_auth() problem occurred when the api_key value sent with the request was not empty and both settings.DEBUG_SKIP_API_KEY_CHECK == settings.DEBUG_SKIP_API_KEY_CHECK == False and there was no matching or enabled api_client registered in the DB.

@yk yk added the backend label Dec 28, 2022
@andreaskoepf andreaskoepf merged commit 11f2491 into main Dec 28, 2022
@andreaskoepf andreaskoepf deleted the 55_backend_HTTP_error_feedback branch December 28, 2022 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Better error feedback to the frontends
2 participants