Skip to main content

Errors

Similar to the familiar "404 Not Found" and "500 Internal Server Error" status codes you may have seen in HTTP, Connect uses a set of 16 error codes. In the Connect protocol, an error is always represented as JSON, and is easily readable in the developer tools of your browser. For example:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"code": "invalid_argument",
"message": "sentence cannot be empty"
}

With the gRPC-web protocol, errors are usually not human-readable, but Connect-Web provides a common type that represents errors consistently across all supported protocols.

Working with errors

All errors are represented by ConnectError, a subtype of the built-in Error class. Using a try-catch block, we can catch any error that occurred during a call:

import { ConnectError } from "@bufbuild/connect-web";

try {
await client.say({sentence: ""});
} catch (err) {
// We have to verify err is a ConnectError
// before using it as one.
if (err instanceof ConnectError) {
err.code; // Code.InvalidArgument
err.message; // "[invalid_argument] sentence cannot be empty"
}
}

Error codes

The code property holds one of Connects error codes. All error codes are available through the TypeScript enumeration Code. Note that a code is an integer value, but can easily be converted to and from a string value.

import { Code, codeToString, codeFromString } from "@bufbuild/connect-web";

let code = Code.InvalidArgument;
code; // 3
codeToString(code); // "invalid_argument"
codeFromString("invalid_argument") // 3

Error messages

The message property contains a descriptive error message. In most cases, the message is provided by the backend implementing the service. Because message is the only property that shows up in the browser console for uncaught errors, the error message is always prefixed with the error code. In case you do want the original error message without a code prefix, use the property rawMessage.

err.message; // "[invalid_argument] sentence cannot be empty"
if (err.code == Code.InvalidArgument) {
err.rawMessage; // "sentence cannot be empty"
}

Metadata

If you catch an error, your program takes an exception from the regular code path, but you might still want to access a header or trailer value. Connect-Web provides a union of header and trailer values in the metadata property as a simple Headers object:

err.metadata.get("Custom-Header-Value");
err.metadata.get("Custom-Trailer-Value");

Error details

On the wire, error details are wrapped with google.protobuf.Any, so that a server or middleware can attach arbitrary data to an error. Using the function connectErrorDetails(), you can decode the details from an error.

The first argument to the function is the error object. The second argument is the message type you expect to see. The return value is an array of zero or more instances of the type.

This example looks up a localized error message in the users preferred language:

import {ConnectError, connectErrorDetails} from "@bufbuild/connect-web";
import {LocalizedMessage} from "./error_details_pb.js";

function handle(err: ConnectError) {
const localized = connectErrorDetails(err, LocalizedMessage)
.find(i => i.locale === navigator.language);
console.log(localized?.message);
}

We are using the protobuf message google.rpc.LocalizedMessage in this example, but any protobuf message can be transmitted as error details.