- A timeout as the third-party service is experiencing issues or is down.
- An improperly formatted request due to user error or a non-fatal software bug.
- A runtime error due to a system state or an “unexpected” error.
Error types
In this section, we dive into how to handle API errors when using the Fireblocks API, in terms of best practices and common pitfalls. As the Fireblocks API uses HTTP requests to send the calls, we will look into three main error types:How to handle unspecified errors: While we do our best to cover all the errors that are possible, and are constantly improving error reporting, you might encounter an error you did not read about in this guide, or the approach and best practices do not suffice.We recommend reading the message that accompanies every Fireblocks API error, as these are usually descriptive and can help pinpoint the issue.
Non-HTTP errors
Non-HTTP errors are a broad error type that relates to anything that is not specifically a response back from the Fireblocks API. As a result, this error type may contain many individual errors that can typically be resolved with the relevant third-party documentation. Examples of such errors include:- Errors that prevent the execution of
.jsor.py(or any other extension) files such ascommand not found, orNo such file or directory - Errors relating to internal formatting of a file (missing indent, missing bracket,
==instead of===) - Errors relating to system state, such as lack of memory, or network connectivity issues
Private key corruption
Observe the following error message: (If you are unfamiliar with this error, a Google search will yield many results pointing to authentication problems.)-
Verify that the file being used is indeed a private key.
A private key typically looks like this:
- Verify that the private key is intact.
-
Generate something out of the private key using OpenSSL.
This command will attempt to convert the private key into its corresponding public key:
openssl rsa -in <api-private-key>.key -puboutA valid response will look something like this:
4xx status codes
4xx status codes are returned as part of an HTTP request to indicate a problem on the client’s side. In the context of this article, it means there is an issue with the request you sent. We will look into four specific status codes and how to handle each of them:- 400 - Bad request - Indicates that the API request itself is incorrect and contains invalid or incorrect values.
- 401 - Unauthorized - Indicates that the API request is sent with invalid authentication information (for example, a bad JWT).
- 403 - Forbidden - Indicates that the API request is trying to perform something the user is not allowed to do.
- 404 - Not found - Indicates that the API request is trying to query a page that does not exist.
429 Too many requests is caused by breaking the rate limits. For more information, see the Working with rate limits article.
The example code below illustrates how to approach each scenario. It might contain functions or types that are not explicitly written out; where that happens, we describe what they do after the code sample. No such type or function exists in the SDK — they merely illustrate a logical container for an operation.
Throughout each error handling section, the examples assume that:
- The user input may not be valid, whether through a function call or direct integration.
- The network connection is functioning as expected.
- The system has sufficient resources (memory and disk space).
400 - Bad request
As mentioned above, 400 response codes indicate that the request you sent contains incorrect information or is invalid.400 example - Bad request
Your internal database links users per asset public keys with their internal database reference (for example, their user ID). To do this, upon registration or upon some update, your code calls the followinggetPublicKey\ get_public_key function with the asset supplied by the user:
BTC1 instead of BTC). Your code will receive the following error:
try{}catch{}\ try:...except... block. This can be used to handle the error in the proper way, like notifying the user or adjusting the input parameters before attempting the call again.
The following is an example of how these types of 400-based errors can be handled for the specific scenario we described:
code which represents the error code returned for the request. Each error code indicates a different issue with the request.
Refer to our API responses page to learn more.
The Fireblocks Python SDK does this seamlessly for 4xx and 5xx errors, so handling should only consider the error code or message.
Handling a 400 error
When a 400 response is returned from the Fireblocks API, you will receive the following message:- Identify the features/components you’re using - Are you performing wallet-specific operations (whitelisting, creating a new wallet, adding a deposit address to a wallet, etc.)?
- Identify the user / system-provided inputs - What is constant? What is received as part of the system state (a database query, a read from a file, etc.)? What is received from user input?
- Identify the potential errors from the API responses page.
Implementing 400 error handling
The code sample and general flow below are customizable to fit your code, business logic, or existing implementation. Adapt the code to your preferred language, as well as your business-specific practices, regulations, and systems. Treat the errors the same way: those written in this section are examples and should be changed to work with your flow. The most important takeaway is to identify the components you’ll be using and what potential errors might occur based on the input you receive. For example, you’re working on a system that receives a request from a user to perform a withdrawal of some amount of a given asset from their Fireblocks asset wallet address.- Refresh the balance of the specific asset they want to withdraw from the vault account assigned to this user - using the refresh asset balance data operation.
- Create a transaction to send the asset from their vault account to the target address - using the create transaction operation.
vaultAccountId) and an asset (assetId), while the create transaction has many potential parameters. You can narrow down the cause of the error by going through each operation’s requirements for your desired end result.
- The refresh asset balance data operation requires a valid vault account ID and a valid asset.
- The create transaction operation requires:
- A valid asset (can be assumed valid after operation #1 takes place)
- A valid amount of said asset (which does not exceed what they have in the wallet)
- A valid target address
1503- invalid asset11001- invalid vault account id
Monitoring transaction status: The failures caused by amount and destination address values are not covered in this guide. For more information about these specific errors, see Monitoring transaction status.
- Lines 4-6: Performs checks on the user. (This depends on your business logic.)
- Lines 7-9: Performs validation of the
toaddress. Using the asset, you’ll see the format of the address to expect. You’ll have to define this more thoroughly, however, there are libraries that already provide this functionality.- Example: BTC SegWit will start with
bc1, and EVM-based chains will be a 40-character hex (with0xprefix and checksummed). You’ll have to define this more thoroughly, however, there are libraries that already provide this functionality.
- Example: BTC SegWit will start with
- Line 11: Get the vault account id for the user. Similar to #1 it depends on your business logic and specific setup.
- Lines 13-17: Refresh the balance of the provided information (asset and vault account ID), using the try and catch you catch any exceptions, and send them to the generic API handler (this is also specific to your implementation, the way it’s described here might not be the correct way to handle it in your code). If there was an error, with one of the expected, we return some descriptive error message which can be changed to explain to the user what to do.
- Lines 22-36: Build the withdrawal transaction.
- Lines 39-43: Send the transaction. Refer to our generic handler for any error generated from creating the transaction.
Fixing live error code 11001: The handling of error code
11001 (invalid vault account) does not directly apply to live scenarios. In this example, the vault account ID is derived from a mock database. In live scenarios, you will need to decide how to fix this yourself.401 - Unauthorized
This error, though not common, occurs when a request contains a missing, invalid, or otherwise incorrect JWT, and therefore the transaction fails. Different codes indicate different reasons for the error caused in the JWT. Unless there is a widespread issue with the SDKs themselves, 401 error response codes will only result from:- Signing with a different user’s private key (e.g. signing with another API user’s key instead of yours)
- Signing with the correct private key, but the incorrect User ID.
403 - Forbidden
For specific API calls, such as get audit logs or list users, you might receive HTTP status code 403. This is uncommon, since the API currently does not include user-change capabilities and only a small number of operations can trigger 403. If you think you might run into this error, test the code before moving it to production. This makes certain that your API user has the permissions needed. Refer to the API responses page to review specific 403 errors.404 - Not Found
A very common error code, “404 not found”, indicates that the page you were looking for does not exist. This error message type states that whatever query you performed, or whatever information you wanted to get, does not exist. How to address such an issue:- Identify what’s missing - These errors usually happen with GET requests, more than with other HTTP methods, and those GET requests are usually no more than 3 different arguments (with some exceptions), to help you pinpoint which one is “incorrect”.
- Address the missing data by either regenerating it using a new Fireblocks API call or raising an exception/error to notify upstream whoever sent this data.
true, otherwise, this value is false.
Using the Find a vault account by ID API reference, you know this specific call uses the vault feature, so you can quickly identify the likely one:
1004- No vault account by that Id
-
Lines 4-6: Check the existence of such a
userId -
Line 8: Finds the vault account correlated to this
userId- Let’s assume, in this case, that if no such vault account exists in your internal database, you need to add a new entry incrementing from the last added vault account id
-
Lines 9-14: Gets the vault account and counts the number of assets. Returns based on our previous explanation (at most 10).
If there is an error, handle using the generic error handler. If there is an error code
1004, you’ll receive a specific type of error. This type of error, in our scenario, will generate a new vault account by something upstream from where the error occurred.
500 status code
A 500 status code indicates that an issue occurred on the server side. Because of this, we cannot provide a way to handle such errors in the same manner as we did for the 4xx errors. We suggest the following:- Do not immediately attempt the request again.
- Double-check the parameters you’re passing. One of them might not be formatted correctly, resulting in a failure in our backend.
- Check the status page to see if there is an ongoing issue.
- Open a Support ticket or reach out to Support on Slack to address the issue.
Common validations to perform
Generally, validations should be done based on your needs and as soon as you have sufficient details to validate them. This will divide into two potential scenarios (but not limited to those two):- You received the value and can immediately perform validation on that value
- You received the value but some additional data is required before performing the validation
- Asset validation - When getting an asset, always verify that the asset is indeed a supported one. More information can be found in the supported assets API reference.
-
OTA validation - When using one-time address, which is received from the user themselves, ensure that the format of the address matches the format of the network.
- For example, BTC SegWit will require an address starting with
bc1and complying with Bech32 formatting. EVMs will be a 40-character checksummed hex string with a prefix of0x.
- For example, BTC SegWit will require an address starting with
-
Amount validation - In cases where you allow users to specify amounts, such as partial withdrawal uses, you’ll always need to:
- Get the current balance available for the user, either via an API call or via an internal ledger (depending on your business logic).
- Verify that the amount is a positive decimal value in the range of (0, retrieved balance] (excluding 0).
- Vault account validation - Ensure the vault account is a non-negative integer. You might want to add restrictions (both in your Transaction Authorization Policy and in your code, to prevent access to vault accounts you don’t want users to be able to access).