Skip to content

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.

Error response format

FieldDescription
codeThe gRPC status code for the error, as a number. The HTTP status of the response is derived from it. See Status codes.
messageA human-readable description of the error. Don't parse it; it can change.
detailsAn 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:

{
    "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:

codegRPC statusHTTP statusTypical cause
3INVALID_ARGUMENT400A field is missing, malformed, or out of range. Fix the request before you retry.
9FAILED_PRECONDITION400The resource isn't in a state that allows the action, for example deleting a policy rule that's still pending approval.
16UNAUTHENTICATED401The access token is missing, invalid, or expired. Request a new token and retry.
7PERMISSION_DENIED403The credential's type or permissions don't cover the operation or the resource.
5NOT_FOUND404The resource doesn't exist, or your credential can't see it.
6ALREADY_EXISTS409An equivalent resource already exists, for example a webhook with the same name or a second limit of the same type on a wallet.
12UNIMPLEMENTED501The path doesn't support the HTTP method, for example PUT or PATCH on a webhook. The message is Method Not Allowed.
13INTERNAL500An unexpected server error. Contact support with the requestId if it persists.
14UNAVAILABLE503The 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.

ServiceArea
PAL000Common errors shared by all services, such as authentication and permissions
PAL001Devices
PAL002MPC quorums and wallet keys
PAL003Approvals
PAL004API credentials
PAL005HSM keystore
PAL006Policies
PAL007Connections
PAL008Balances
PAL009Vaults and wallets
PAL010Transactions
PAL011Organizations and users
PAL012Identity
PAL013Address book
PAL014Compliance
PAL015Webhooks
PAL016Backups
PAL017Workflows, including asset sweeping
PAL018Audit logging
PAL019Blockchain connections
PAL020Registry

Common errors

These reason codes can come from any endpoint:

ReasonMessageWhat to do
PAL000.001unauthenticated requestSend a valid access token in the Authorization header. A missing, malformed, or expired token returns 401 with no reason code.
PAL000.002unauthorized requestCheck that the credential's type and permissions cover the operation and the vault or wallet you're accessing. See Manage API credentials.
PAL000.003invalid permissionThe credential's permissions are malformed. Recreate the credential.
PAL000.008unsupported blockchainUse a blockchain that Ripple Custody (Wallet) supports. See Supported blockchains and tokens.
PAL000.010invalid assetCheck the asset symbol, issuer, or contract.
PAL000.012invalid addressCheck that the address is valid for the wallet's blockchain.
PAL000.013invalid asset IDCheck the asset ID format.
PAL000.014invalid signatureCheck the signed payload and signature.
PAL000.015invalid tokenRequest a new access token.
PAL000.020invalid requestThe 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.

Errors documented with their features

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

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.

Authentication

You seeReasonCauseWhat to do
400 invalid request from POST /v2/credentials/oauth/tokenPAL000.020The 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.
401 Unauthorized, with no detailsNoneThe Authorization header is missing, or the token is malformed or expired.Request a new token and send it as Authorization: Bearer <accessToken>.
403 unauthorized requestPAL000.002The 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.

Permissions

You seeReasonCauseWhat to do
403 on the policy rules endpoints (/policy-rules), while the wallet limit endpoints workPAL000.002The 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.
403 on freeze, unfreeze, or a sweep triggerPAL000.002The request doesn't use a TRANSACTIONS credential.Use a TRANSACTIONS credential.
403 on an operation that the credential type coversPAL000.002The 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.

Validation

You seeReasonCauseWhat to do
400 invalid requestPAL000.020A 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.
400 invalid request on a list requestPAL000.020The 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 and 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 ErrorInfoNoneA 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.
501 Method Not AllowedNoneThe 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 seeReasonCauseWhat to do
404 vault not foundPAL009.002No vault in your organization has this ID.Check the vault ID.
404 on a walletPAL009.101No 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 walletPAL009.110blockchain is missing or isn't a supported value.Set blockchain, for example to XRP_LEDGER. See Create a wallet.
400 MPC wallet creation requires quorum_idPAL009.108An MPC wallet create request has no quorumId.Pass the ID of a confirmed quorum.
400 wallet is not provisionedPAL009.106You requested the sequence of a wallet that isn't PROVISIONED.Wait until the wallet is PROVISIONED.
400 invalid request on PUT .../settingsPAL000.020The settings object is empty.Send all four settings. Any setting you omit is set to false. See Update wallet settings.
200 with an empty list for a vault's wallets, or for a vault's or wallet's balancesNoneThe 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 seeReasonCauseWhat to do
404 transaction not foundPAL010.004The 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.
400 blockchain override is only allowed between EVM-compatible chainsPAL010.009A 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.
400 connector data request rejected on a fee estimatePAL020.004On Ethereum, the originAddress has no funds.Fund the origin wallet, and then estimate again.
400 invalid encoded transaction on a raw transactionPAL010.011The EVM encodedTransaction can't be decoded.Check the encoding. See Transaction encoding formats.
400 xrp ledger orchestrator rejected the transaction on a raw transactionPAL010.022The XRP Ledger encodedTransaction can't be decoded.Check the encoding. See Transaction encoding formats.
400 cannot freeze/unfreeze transactionPAL010.008The 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.
400 invalid request on freeze or unfreezePAL000.020reason 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-servicePAL006.005Your 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.
Status FAILED with an empty problems arrayNoneThe 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 seeReasonCauseWhat to do
409 limit policy already existsPAL006.023The 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.
400 on deleting a wallet limitPAL006.016The 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 valuePAL006.028A matcher value isn't valid, for example a COUNTERPARTY_ID that isn't a UUID.Check the matcher values. See Matchers.
400 invalid request on a wallet limitPAL000.020The 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.
403 on the policy rules endpointsPAL000.002The credential doesn't have the policy:* permissions.See Permissions.

Address book

You seeReasonCauseWhat to do
400 address is not compatible with one or more selected blockchainsPAL013.015The address isn't valid on every blockchain in blockchains.Check the address and the blockchains list. See Add an address to a counterparty.
404 on a counterpartyPAL013.002No counterparty has this ID.Check the counterparty ID.
404 on an addressPAL013.012No address has this ID under the counterparty in the path.Check the address ID and its counterparty.
400 not allowed on deleting an addressPAL013.021The address doesn't belong to the counterparty in the path.Use the address's own counterparty ID. See Get or delete an address.
400 invalid request on a counterparty or addressPAL000.020A 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.

Webhooks

You seeReasonCauseWhat to do
409 webhook already existsPAL015.001Another webhook has the same name. Webhooks can share an endpoint, but not a name.Use a different name.
409 subscription already existsPAL015.010The webhook already has a subscription for this domain.List the webhook's subscriptions before you add one.
404 on a webhookPAL015.002No webhook has this ID.Check the webhook ID.
404 on a subscriptionPAL015.011No subscription with this ID exists on the webhook.Check the subscription ID and the webhook ID.
400 invalid request on a webhook or subscriptionPAL000.020The 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 subscriptionsNoneThe body isn't an array.Send the subscriptions as a JSON array. See Add subscriptions.
200 on deleting a webhook or subscription that doesn't existNoneDeletes return 200 whether or not the object existed.Don't treat a 200 as proof that the object existed.

Sweeps

You seeReasonCauseWhat to do
400 sweep configuration already runningPAL017.006A sweep for this configuration is already running.Wait for the current run to finish, then trigger the sweep again. See Trigger a sweep.
400 invalid request on a sweep triggerPAL000.020The configuration ID isn't a UUID.Check the configuration ID.
403 on a sweep triggerPAL000.002The request doesn't use a TRANSACTIONS credential.Use a TRANSACTIONS credential.
200 with no transactions for a sweep instanceNoneNo 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 with the requestId, the reason code, and the time of the request.