# Error codes

When a Ripple Custody (Wallet) API request fails, the response has an HTTP error status and a JSON body that describes the error. This page explains the body, how its `code` maps to the HTTP status, how to read the `PAL` reason codes, and how to fix common errors. For general API conventions, including authentication and retries, see [API conventions](/pt-br/products/wallet/api-and-developer-experience/api-conventions#errors).

## Error response format

| Field | Description |
|  --- | --- |
| `code` | The gRPC status code for the error, as a number. The HTTP status of the response is derived from it. See [Status codes](#status-codes). |
| `message` | A human-readable description of the error. Don't parse it; it can change. |
| `details` | An array of objects, each identified by `@type`. The API returns at most two kinds of entry. A `401` response has no `details`. |


The `details` array can contain:

- **`ErrorInfo`** (`type.googleapis.com/google.rpc.ErrorInfo`): `reason` is a `PAL` reason code that identifies the specific problem. `domain` is the API host that produced the error, such as `api.sandbox.palisade.co`. `metadata` is an object that is usually empty. Request validation errors include an `ErrorInfo` entry with reason `PAL000.020` and the generic message `invalid request`, which doesn't name the field. Some errors have no `ErrorInfo` entry: a body or query parameter that the API can't parse (the `message` is the parser error), and a method that the path doesn't support.
- **`RequestInfo`** (`type.googleapis.com/google.rpc.RequestInfo`): `requestId` identifies the request. Every error response includes it except a `401`, whose body is only `{"code": 16, "message": "Unauthorized"}`.


### Example

This response comes from a request whose credential doesn't have permission for the operation:

```json
{
    "code": 7,
    "message": "unauthorized request",
    "details": [
        {
            "@type": "type.googleapis.com/google.rpc.ErrorInfo",
            "reason": "PAL000.002",
            "domain": "api.sandbox.palisade.co",
            "metadata": {}
        },
        {
            "@type": "type.googleapis.com/google.rpc.RequestInfo",
            "requestId": "c817569e-b765-4e6e-a3af-bdb1d07e7517",
            "servingData": ""
        }
    ]
}
```

## Status codes

The `code` field uses gRPC status codes. Ripple Custody (Wallet) maps them to HTTP statuses as follows:

| `code` | gRPC status | HTTP status | Typical cause |
|  --- | --- | --- | --- |
| `3` | `INVALID_ARGUMENT` | `400` | A field is missing, malformed, or out of range. Fix the request before you retry. |
| `9` | `FAILED_PRECONDITION` | `400` | The resource isn't in a state that allows the action, for example deleting a policy rule that's still pending approval. |
| `16` | `UNAUTHENTICATED` | `401` | The access token is missing, invalid, or expired. Request a new token and retry. |
| `7` | `PERMISSION_DENIED` | `403` | The credential's type or permissions don't cover the operation or the resource. |
| `5` | `NOT_FOUND` | `404` | The resource doesn't exist, or your credential can't see it. |
| `6` | `ALREADY_EXISTS` | `409` | An equivalent resource already exists, for example a webhook with the same name or a second limit of the same type on a wallet. |
| `12` | `UNIMPLEMENTED` | `501` | The path doesn't support the HTTP method, for example `PUT` or `PATCH` on a webhook. The `message` is `Method Not Allowed`. |
| `13` | `INTERNAL` | `500` | An unexpected server error. Contact support with the `requestId` if it persists. |
| `14` | `UNAVAILABLE` | `503` | The service is temporarily unavailable. |


## Reason codes

A reason code has the form `PAL<service>.<problem>`. The three-digit service number identifies the area of the platform that rejected the request, and the problem number identifies the specific error within it. Reason codes are stable, so use them, not `message`, when your code handles specific errors.

| Service | Area |
|  --- | --- |
| `PAL000` | Common errors shared by all services, such as authentication and permissions |
| `PAL001` | Devices |
| `PAL002` | MPC quorums and wallet keys |
| `PAL003` | Approvals |
| `PAL004` | API credentials |
| `PAL005` | HSM keystore |
| `PAL006` | Policies |
| `PAL007` | Connections |
| `PAL008` | Balances |
| `PAL009` | Vaults and wallets |
| `PAL010` | Transactions |
| `PAL011` | Organizations and users |
| `PAL012` | Identity |
| `PAL013` | Address book |
| `PAL014` | Compliance |
| `PAL015` | Webhooks |
| `PAL016` | Backups |
| `PAL017` | Workflows, including asset sweeping |
| `PAL018` | Audit logging |
| `PAL019` | Blockchain connections |
| `PAL020` | Registry |


### Common errors

These reason codes can come from any endpoint:

| Reason | Message | What to do |
|  --- | --- | --- |
| `PAL000.001` | unauthenticated request | Send a valid access token in the `Authorization` header. A missing, malformed, or expired token returns `401` with no reason code. |
| `PAL000.002` | unauthorized request | Check that the credential's type and permissions cover the operation and the vault or wallet you're accessing. See [Manage API credentials](/pt-br/products/wallet/organization-and-access/api-credentials/manage-api-credentials). |
| `PAL000.003` | invalid permission | The credential's permissions are malformed. Recreate the credential. |
| `PAL000.008` | unsupported blockchain | Use a blockchain that Ripple Custody (Wallet) supports. See [Supported blockchains and tokens](/pt-br/products/wallet/vaults-and-wallets/supported-blockchains-and-tokens). |
| `PAL000.010` | invalid asset | Check the asset symbol, issuer, or contract. |
| `PAL000.012` | invalid address | Check that the address is valid for the wallet's blockchain. |
| `PAL000.013` | invalid asset ID | Check the asset ID format. |
| `PAL000.014` | invalid signature | Check the signed payload and signature. |
| `PAL000.015` | invalid token | Request a new access token. |
| `PAL000.020` | invalid request | The request failed validation: a required field is missing or empty, a value is out of range or not in an allowed format, or an enum value isn't recognized. Also returned by the token exchange for a wrong `clientId` or `clientSecret`. Check the request against the [API reference](/pt-br/products/wallet/api-docs/palisade-api/palisade-api). |


### Errors documented with their features

Pages that document a feature also list the reason codes it returns:

- Policies (`PAL006`): [Policy reference](/pt-br/products/wallet/governance-and-controls/policies/policy-reference#error-codes) and [Policy rules](/pt-br/products/wallet/governance-and-controls/policies/policy-reference#error-codes)
- Failed transactions: transactions carry a `problems` array with reason codes and retryability. See [Transaction problems](/pt-br/products/wallet/api-and-developer-experience/api-conventions#transaction-problems).


## Troubleshoot common errors

These tables list errors that the API returns in practice, grouped by area, with their likely cause and fix. Some requests succeed when you might expect an error, so the tables also include a few `200` responses that usually mean something went wrong. For more behaviors to plan for, see [Behaviors to know](/pt-br/products/wallet/api-and-developer-experience/api-conventions#behaviors-to-know).

### Authentication

| You see | Reason | Cause | What to do |
|  --- | --- | --- | --- |
| `400` `invalid request` from `POST /v2/credentials/oauth/token` | `PAL000.020` | The `clientId` or `clientSecret` is wrong, or the body is missing. The token exchange doesn't return `401`. | Check that you send the credential's `clientId` and `clientSecret` in a JSON body. See [Get and use an access token](/pt-br/products/wallet/api-and-developer-experience/api-conventions#get-and-use-an-access-token). |
| `401` `Unauthorized`, with no `details` | None | The `Authorization` header is missing, or the token is malformed or expired. | Request a new token and send it as `Authorization: Bearer <accessToken>`. |
| `403` `unauthorized request` | `PAL000.002` | The credential's type doesn't cover the endpoint, for example a `MONITORING` credential calling `GET /v2/vaults`. | Use a credential of the type that covers the endpoint. See [Credential types](/pt-br/products/wallet/api-and-developer-experience/api-conventions#credential-types). |


### Permissions

| You see | Reason | Cause | What to do |
|  --- | --- | --- | --- |
| `403` on the policy rules endpoints (`/policy-rules`), while the wallet limit endpoints work | `PAL000.002` | The `CONTROLS` credential doesn't have the `policy:*` permissions. The wallet limit endpoints use the separate `keylimit:*` permissions. | Grant the credential the policy permissions it needs. See [Manage policy rules via the API](/pt-br/products/wallet/governance-and-controls/policies/manage-policies-api#prerequisites). |
| `403` on freeze, unfreeze, or a sweep trigger | `PAL000.002` | The request doesn't use a `TRANSACTIONS` credential. | Use a `TRANSACTIONS` credential. |
| `403` on an operation that the credential type covers | `PAL000.002` | The credential's permissions don't include the operation, or the vault or wallet you're accessing. | Check the credential's permissions in the console. See [Manage API credentials](/pt-br/products/wallet/organization-and-access/api-credentials/manage-api-credentials). |


### Validation

| You see | Reason | Cause | What to do |
|  --- | --- | --- | --- |
| `400` `invalid request` | `PAL000.020` | A required field is missing or empty, a value is out of range or in the wrong format, or an ID in the path isn't a UUID. The message doesn't name the field. | Check the request against the [API reference](/pt-br/products/wallet/api-docs/palisade-api/palisade-api). |
| `400` `invalid request` on a list request | `PAL000.020` | The page size is above the maximum (1,000, or 100 for the top-level `pageSize` on some operations), `pagination.orderBy` isn't a snake_case sortable field (for example `createdAt` instead of `created_at`), or a filter value isn't recognized. | Fix the paging, sorting, or filter parameter. See [Pagination](/pt-br/products/wallet/api-and-developer-experience/api-conventions#pagination) and [Filtering, search, and sorting](/pt-br/products/wallet/api-and-developer-experience/api-conventions#filtering-search-and-sorting). |
| `400` with a parser message, such as `invalid path: "domain" is not a message` or `invalid value for string field search`, and no `ErrorInfo` | None | A filter has an operator it doesn't take, a filter that needs an operator has none, or a body field has the wrong type, for example an object where the API expects an array or a string. | Check the filter form and the field types. See [Filters that take a bare value](/pt-br/products/wallet/api-and-developer-experience/api-conventions#filters-that-take-a-bare-value). |
| `501` `Method Not Allowed` | None | The path doesn't support the HTTP method, for example `DELETE` on a vault, or `PUT` or `PATCH` on a webhook. | Use a supported method. To change a webhook, delete it and create a new one. |


### Vaults and wallets

| You see | Reason | Cause | What to do |
|  --- | --- | --- | --- |
| `404` `vault not found` | `PAL009.002` | No vault in your organization has this ID. | Check the vault ID. |
| `404` on a wallet | `PAL009.101` | No wallet has this ID, or the wallet isn't in the vault in the path. | Check the wallet ID and its `vaultId`, or get the wallet with `GET /v2/wallets/{id}`. |
| `400` `unsupported blockchain` when you create a wallet | `PAL009.110` | `blockchain` is missing or isn't a supported value. | Set `blockchain`, for example to `XRP_LEDGER`. See [Create a wallet](/pt-br/products/wallet/vaults-and-wallets/wallets/manage-wallets-api#create-a-wallet-via-the-api). |
| `400` `MPC wallet creation requires quorum_id` | `PAL009.108` | An MPC wallet create request has no `quorumId`. | Pass the ID of a confirmed quorum. |
| `400` `wallet is not provisioned` | `PAL009.106` | You requested the sequence of a wallet that isn't `PROVISIONED`. | Wait until the wallet is `PROVISIONED`. |
| `400` `invalid request` on `PUT .../settings` | `PAL000.020` | The `settings` object is empty. | Send all four settings. Any setting you omit is set to `false`. See [Update wallet settings](/pt-br/products/wallet/vaults-and-wallets/wallets/manage-wallets-api#update-wallet-settings-via-the-api). |
| `200` with an empty list for a vault's wallets, or for a vault's or wallet's balances | None | The vault or wallet ID doesn't exist. These list and balance requests don't return `404`. | Get the vault or wallet by ID to check that it exists. |


### Transactions

| You see | Reason | Cause | What to do |
|  --- | --- | --- | --- |
| `404` `transaction not found` | `PAL010.004` | The transaction ID doesn't exist or belongs to a different wallet, or a transfer reuses an `externalId` already used on a different wallet. | Check the transaction ID and the wallet in the path. Use a new `externalId` for each transfer. See [External IDs](/pt-br/products/wallet/api-and-developer-experience/api-conventions#external-ids). |
| `400` `blockchain override is only allowed between EVM-compatible chains` | `PAL010.009` | A transfer sets `blockchain` on a non-EVM wallet, or to a non-EVM chain. | Remove `blockchain`, or set it to an EVM chain for an EVM wallet. See [EVM cross-chain transfers](/pt-br/products/wallet/transactions/send-assets#evm-cross-chain-transfers-via-the-api). |
| `400` `connector data request rejected` on a fee estimate | `PAL020.004` | On Ethereum, the `originAddress` has no funds. | Fund the origin wallet, and then estimate again. |
| `400` `invalid encoded transaction` on a raw transaction | `PAL010.011` | The EVM `encodedTransaction` can't be decoded. | Check the encoding. See [Transaction encoding formats](/pt-br/products/wallet/transactions/raw-signing/encoding-formats). |
| `400` `xrp ledger orchestrator rejected the transaction` on a raw transaction | `PAL010.022` | The XRP Ledger `encodedTransaction` can't be decoded. | Check the encoding. See [Transaction encoding formats](/pt-br/products/wallet/transactions/raw-signing/encoding-formats#xrp-ledger). |
| `400` `cannot freeze/unfreeze transaction` | `PAL010.008` | The transaction is in a state that can't be frozen or unfrozen, such as a rejected outgoing transaction. | Check the transaction's status and `freezeInfo`. See [Freeze and unfreeze transactions via the API](/pt-br/products/wallet/compliance/transaction-freeze-api). |
| `400` `invalid request` on freeze or unfreeze | `PAL000.020` | `reason` is missing, or `mutationId` isn't a UUID. | Pass a `reason`, and pass a UUID as `mutationId`. |
| `200`, then status `REJECTED` with a `problems` entry from `policy-service` | `PAL006.005` | Your policies don't allow the transaction, for example because the wallet's limits for the asset aren't active or the asset has no limit. | Check the wallet's policy rules and limits. See [Track the transaction lifecycle](/pt-br/products/wallet/transactions/view-and-track-transactions#track-the-transaction-lifecycle-via-the-api). |
| Status `FAILED` with an empty `problems` array | None | The blockchain rejected the transaction. `reasons` carries the result, such as `Blockchain status: tecUNFUNDED_PAYMENT`. | Read `reasons`, fix the cause, and send a new transaction. |


### Policies

| You see | Reason | Cause | What to do |
|  --- | --- | --- | --- |
| `409` `limit policy already exists` | `PAL006.023` | The wallet already has a limit with the same limit type, asset, and matchers. A different amount or duration doesn't make it a new limit. | Delete the existing limit, or change the limit type or matchers. See [Policy reference](/pt-br/products/wallet/governance-and-controls/policies/policy-reference#error-codes). |
| `400` on deleting a wallet limit | `PAL006.016` | The limit is still pending approval, or no limit has this ID. | Wait for the approval to complete, or check the limit ID. |
| `400` `invalid matcher value` | `PAL006.028` | A matcher value isn't valid, for example a `COUNTERPARTY_ID` that isn't a UUID. | Check the matcher values. See [Matchers](/pt-br/products/wallet/governance-and-controls/policies/policy-reference#matchers). |
| `400` `invalid request` on a wallet limit | `PAL000.020` | The `duration` is one year or longer, an `ALL_COUNTERPARTIES` matcher has a value, or the matcher uses the deprecated `COUNTERPARTY` type. | Fix the limit. See [Policy reference](/pt-br/products/wallet/governance-and-controls/policies/policy-reference). |
| `403` on the policy rules endpoints | `PAL000.002` | The credential doesn't have the `policy:*` permissions. | See [Permissions](#permissions). |


### Address book

| You see | Reason | Cause | What to do |
|  --- | --- | --- | --- |
| `400` `address is not compatible with one or more selected blockchains` | `PAL013.015` | The address isn't valid on every blockchain in `blockchains`. | Check the address and the `blockchains` list. See [Add an address to a counterparty](/pt-br/products/wallet/governance-and-controls/address-book/manage-address-book-api#add-an-address-to-a-counterparty-via-the-api). |
| `404` on a counterparty | `PAL013.002` | No counterparty has this ID. | Check the counterparty ID. |
| `404` on an address | `PAL013.012` | No address has this ID under the counterparty in the path. | Check the address ID and its counterparty. |
| `400` `not allowed` on deleting an address | `PAL013.021` | The address doesn't belong to the counterparty in the path. | Use the address's own counterparty ID. See [Get or delete an address](/pt-br/products/wallet/governance-and-controls/address-book/manage-address-book-api#get-or-delete-an-address-via-the-api). |
| `400` `invalid request` on a counterparty or address | `PAL000.020` | A required field is missing or invalid, for example a counterparty without `name`, or an address with an empty `blockchains` list. | Check the request against the [API reference](/pt-br/products/wallet/api-docs/palisade-api/palisade-api). |


### Webhooks

| You see | Reason | Cause | What to do |
|  --- | --- | --- | --- |
| `409` `webhook already exists` | `PAL015.001` | Another webhook has the same name. Webhooks can share an endpoint, but not a name. | Use a different name. |
| `409` `subscription already exists` | `PAL015.010` | The webhook already has a subscription for this domain. | List the webhook's subscriptions before you add one. |
| `404` on a webhook | `PAL015.002` | No webhook has this ID. | Check the webhook ID. |
| `404` on a subscription | `PAL015.011` | No subscription with this ID exists on the webhook. | Check the subscription ID and the webhook ID. |
| `400` `invalid request` on a webhook or subscription | `PAL000.020` | The endpoint is missing or doesn't use `https://`, or a subscription domain isn't recognized. | Use an `https://` endpoint and a valid domain, such as `TRANSACTION`. |
| `400` with a parser message on adding subscriptions | None | The body isn't an array. | Send the subscriptions as a JSON array. See [Add subscriptions](/pt-br/products/wallet/integrations-and-monitoring/webhooks/manage-webhooks-api#add-subscriptions-via-the-api). |
| `200` on deleting a webhook or subscription that doesn't exist | None | Deletes return `200` whether or not the object existed. | Don't treat a `200` as proof that the object existed. |


### Sweeps

| You see | Reason | Cause | What to do |
|  --- | --- | --- | --- |
| `400` `sweep configuration already running` | `PAL017.006` | A sweep for this configuration is already running. | Wait for the current run to finish, then trigger the sweep again. See [Trigger a sweep](/pt-br/products/wallet/vaults-and-wallets/asset-sweeping/trigger-asset-sweeps-api#trigger-a-sweep-via-the-api). |
| `400` `invalid request` on a sweep trigger | `PAL000.020` | The configuration ID isn't a UUID. | Check the configuration ID. |
| `403` on a sweep trigger | `PAL000.002` | The request doesn't use a `TRANSACTIONS` credential. | Use a `TRANSACTIONS` credential. |
| `200` with no transactions for a sweep instance | None | No sweep instance has this ID. | Check the sweep instance ID in the console's sweep run history. |


## Get help with an error

Log the `requestId` from every error response. If you can't resolve an error, contact [Ripple Support](https://technicalsupport.ripple.com/) with the `requestId`, the reason code, and the time of the request.