Errors

The Actions use the same error mechanism as any other Go function.

When an Action returns an error, its execution ends immediately and the client receives the error as the second element of the result.

There is no need to build error responses manually.


Return an error

An Action can return any value that implements the interface error.

gox
func Login() gox.Action {
    return errors.New("Invalid credentials")
}
typescript
const [result, err] = await Actions.Login()

console.log(result)
// null

console.log(err)
// GoxActionError

When an Action returns an error, the return value will always be null.


Errors during execution

It is common to return errors produced by other functions.

gox
func GetUser(id string) gox.Action {
    user, err := database.FindUser(id)

    if err != nil {
        return err
    }

    return user
}

It is not necessary to transform the error before returning it.

However, before returning an external error directly, it must be checked that your message is safe for the client.


Create Errors

Errors can be created using any usual Go mechanism.

gox
return errors.New("Access denied")

It is also possible to return errors built with additional information.

gox
return fmt.Errorf(
    "User %s not found",
    id,
)

GOX does not impose a specific type to represent errors.

When sending it to the client, GOX uses the text produced by the method Error().


Client

The Actions always return a tupla.

typescript
const [user, err] = await Actions.GetUser(id)

When the Action completes successfully:

typescript
user !== null

err === null

When a mistake occurs:

typescript
user === null

err instanceof Error

The errors of the Actions are instances of GoxActionError, a type that extends the native object Error.

typescript
const [user, err] =
    await Actions.GetUser(id)

if (err) {
    console.log(err.name)
    // GoxActionError

    console.log(err.message)
    // User not found

    console.log(err.type)
    // ACTION_ERROR

    console.log(err.action)
    // GetUser

    return
}

console.log(user.name)

It is advisable to check first if there is an error before using the result.


Error information

An instance of GoxActionError may contain the following properties:

PropertyDescription
messageMessage received from the server or generated by the client
nameError name: GoxActionError
codeNumeric error code
typeIdentifiable type of error
actionName of the Action invoked
statusAssociated HTTP State
causeOriginal error when generated in the client

The errors returned directly by an Action use the type ACTION_ERROR.

typescript
if (err?.type === "ACTION_ERROR") {
    console.error(err.message)
}

GOX transmits the error message, but does not reconstruct in JavaScript the custom type used in Go or expose the server stack.


Propagation of errors

As the Actions use conventional Go errors, they can be spread using the usual language patterns.

gox
user, err := repository.FindUser(id)

if err != nil {
    return err
}

This allows for the re-use of existing libraries and functions without modification.

Before spreading an error to the client it should be verified that it does not disclose internal information of the application.

When the error contains sensitive details, it is preferable to register it on the server and return a controlled message.

gox
user, err := repository.FindUser(id)

if err != nil {
    log.Printf("failed to find user %q: %v", id, err)

    return errors.New("Unable to retrieve the user")
}

Client errors

GoxActionError It also represents errors that can occur before the Action ends properly.

These include:

  • Undefined actions.
  • Invalid arguments.
  • Network errors.
  • Methods not allowed.
  • Invalid responses.
  • Uncompatible types of response.
  • Internal server errors.

Property type allows them to be distinguished.

typescript
const [result, err] =
    await Actions.SaveUser(user)

if (err?.type === "NETWORK_ERROR") {
    console.log("Unable to connect to the server")
}

Panics

When a panic, GOX interrupts the request and responds with an internal server error.

gox
func CreateReport() gox.Action {
    panic("report generator failed")
}

The client receives a GoxActionError of the type SERVER_ERROR.

typescript
const [report, err] =
    await Actions.CreateReport()

console.log(report)
// null

console.log(err.type)
// SERVER_ERROR

console.log(err.status)
// 500

The internal message of the panic it is not delivered to the client.

GOX records the error on the server, where it can keep useful information to diagnose the problem without publicly exposing it.

The panic should be reserved for unexpected situations. The expected errors should be returned using values error.


Security

Returning errors directly is practical, but you can also reveal information about the internal functioning of the server.

Errors produced by databases, file systems, external services or bookstores may contain:

  • Internal routes.
  • Consultations or table names.
  • Service addresses.
  • Private identifiers.
  • Configuration details.
  • Useful information for infrastructure analysis.

Before returning an error it must be verified that your message is appropriate for the client, especially when the error was not created directly by the application.

When it is necessary to keep the original error, you can register on the server and return a controlled message to the client.


Best practices

  • Returns errors as soon as they are detected.
  • It uses clear and descriptive messages.
  • Always check if there is an error before using the result of an Action.
  • Check that the message is safe before you directly return an error.
  • It pays particular attention to errors from bookstores, databases and external services.
  • It records the internal details on the server and returns controlled messages to the client.
  • Do not depend on custom Go error types in JavaScript, as only the message is transmitted.
  • Use panic only for unexpected situations.
  • Avoid using errors to control the normal flow of the application.

To learn more about ActionsSee your documentation. To learn more about ParametersSee your documentation. To learn more about FormsSee your documentation. To learn more about Return Values, check your documentation.


See also

Next step

Continue with the documentation for Contextwhere you will learn how to access the request, response, session and other features available during the execution of a page or Action.

Context