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

chore(client): use application errors instead of PlatformErrors #2337

Closed
wants to merge 11 commits into from

Conversation

fortuna
Copy link
Collaborator

@fortuna fortuna commented Jan 22, 2025

convertRawErrorObjectToPlatformError is now a place where we can convert from the PlatformError serialized errors to application errors.

Note how it deletes a significant amount of code. We were representing the same errors multiple times.

Before this PR, deserialization had to happen at different places in the code, complicating application code and making it impractical to change serialization. Error deserialization is now centralized, and we need to move away from using PlatformError in application code.

The motivation for this PR was propagating the Provider error from the dynamic key. It has a message and a detailed message, and our application error models exactly that. With PlatformError I will have to create my own schema to encode that in the error, but then the application code had to be aware of that schema as well in order to use the messages correctly, which was problematic.

@fortuna fortuna requested a review from jyyi1 January 22, 2025 00:19
@fortuna fortuna requested a review from a team as a code owner January 22, 2025 00:19
@fortuna fortuna requested a review from sbruens January 22, 2025 00:19
@github-actions github-actions bot added size/S and removed size/M labels Jan 22, 2025
Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

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

We included arbitrary details in the errors, we should forward them to the strongly typed errors as well.

* ipcToAppError converts an Error returned from the MethodChannel IPC to an application error.
* MethodChannel errors encode its information as a JSON object in the Error message.
*/
export function ipcToAppError(ipcError: Error): CustomError {
Copy link
Contributor

Choose a reason for hiding this comment

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

parseAppErrorFromIPC would be better?

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'm not sure about using "parse" here, since the input is an object, not serialized text.

@@ -330,10 +330,6 @@ export class App {
buttonHandler = () => {
this.showErrorDetailsDialog(error.details);
};
} else if (error instanceof PlatformError) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I would keep this. The default handler (showErrorCauseDialog) will print weird outputs (for example, duplicated causes). PlatformError's toString already handles the format and prints a cause chain.

Also the default handler doesn't print out error details Map.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in showErrorCauseDialog.

We shouldn't be using localizeErrorCode anymore, it's not needed.

Copy link
Contributor

@sbruens sbruens Jan 23, 2025

Choose a reason for hiding this comment

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

We shouldn't be using localizeErrorCode anymore, it's not needed.

Where is localization of errors happening now? Are we no longer localizing these errors and just throwing a generic localized "unknown error" for them? That's a regression and is a worse user experience. We should localize the top-level user-facing error that can tell the user what went wrong (like the one suggesting to contact their service provider with details).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We localize the errors in App.showLocalizedError:

showLocalizedError(error?: Error, toastDuration = 10000) {

I'm actually removing the duplicate logic in this PR.

* Returns a JSON string of this error with all details and causes.
* @returns {string} The JSON string representing this error.
*/
toJSON(): string {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is used when initiating a PlatformError from electron main process (not from Go) to renderer process: https://github.com/Jigsaw-Code/outline-apps/blob/master/client/electron/routing_service.ts#L141

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

Ugh... Perhaps we can move the error serialization to Go at some point.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we should move the logic to Go in the future. All errors should be triggered from Go.

client/src/www/model/platform_error.ts Outdated Show resolved Hide resolved
client/src/www/model/platform_error.ts Outdated Show resolved Hide resolved
client/src/www/model/platform_error.ts Outdated Show resolved Hide resolved
@fortuna fortuna requested a review from a team as a code owner January 22, 2025 22:31
@github-actions github-actions bot added size/M and removed size/S labels Jan 22, 2025
Copy link
Collaborator Author

@fortuna fortuna left a comment

Choose a reason for hiding this comment

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

Another look?

* ipcToAppError converts an Error returned from the MethodChannel IPC to an application error.
* MethodChannel errors encode its information as a JSON object in the Error message.
*/
export function ipcToAppError(ipcError: Error): CustomError {
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'm not sure about using "parse" here, since the input is an object, not serialized text.

client/src/www/model/platform_error.ts Outdated Show resolved Hide resolved
* Returns a JSON string of this error with all details and causes.
* @returns {string} The JSON string representing this error.
*/
toJSON(): string {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

Ugh... Perhaps we can move the error serialization to Go at some point.

client/src/www/model/platform_error.ts Outdated Show resolved Hide resolved
client/src/www/model/platform_error.ts Outdated Show resolved Hide resolved
@@ -330,10 +330,6 @@ export class App {
buttonHandler = () => {
this.showErrorDetailsDialog(error.details);
};
} else if (error instanceof PlatformError) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in showErrorCauseDialog.

We shouldn't be using localizeErrorCode anymore, it's not needed.

@fortuna fortuna requested a review from jyyi1 January 22, 2025 23:21
Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

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

Thanks for the update. Added some comments.

// FetchConfigFailed means we failed to fetch a config from a remote location.
FetchConfigFailed ErrorCode = "ERR_FETCH_CONFIG_FAILURE"
// GenericErr indicates a generic error that is not directly surfaced to the user.
GenericErr ErrorCode = "ERR_GENERIC"
Copy link
Contributor

@jyyi1 jyyi1 Jan 23, 2025

Choose a reason for hiding this comment

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

Can we use the InternalError ErrorCode = "ERR_INTERNAL_ERROR" defined above, which has already been widely used across the code base?

@@ -756,7 +750,7 @@ export class App {
private showErrorCauseDialog(error: Error) {
let message = error.toString();

if (error.cause) {
if (!(error instanceof PlatformError && error.cause)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Correct me if I was wrong: if (!(error instanceof PlatformError && error.cause)) <=> if ((error not-instanceof PlatformError) or (!error.cause)), then we show the cause. Is this correct?

constructor(message: string, options?: {cause?: Error}) {
super(message, options);
constructor(cause?: Error) {
super(undefined, {cause});
Copy link
Contributor

Choose a reason for hiding this comment

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

The undefined message seems to be off from the best practice of JavaScript's Error object:

The message data property of an Error instance is a human-readable description of the error.

Maybe we can have a default human-readable message?


// TODO(fortuna): Remove PlatformError from the model.
// PlatformError is an implementation detail. It does not belong in the model.
// It's also about serialization, we should not use it in application code.
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 As we have a unified MethodChannel now, we can convert the errors there, without exporting any internal implementations.

@@ -45,7 +45,7 @@ func fetchResource(url string) (string, error) {
resp.Body.Close()
if resp.StatusCode > 299 {
return "", platerrors.PlatformError{
Code: platerrors.FetchConfigFailed,
Code: platerrors.GenericErr,
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be useful to expose this error details? Especially the HTTP response code?

@fortuna
Copy link
Collaborator Author

fortuna commented Jan 24, 2025

Closing in favor of the simpler #2346

@fortuna fortuna closed this Jan 24, 2025
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.

4 participants