Skip to main content
Look up an error that Permissions returned while you signed, handled an approval, changed approval settings, read policies or published a policy. Each table gives the code, the HTTP status, the server message, what the error means and what to do next.

How errors reach your code

The server attaches a code to every Permissions error, but not every client receives it. The REST API and the REST SDK always return the code. The JavaScript SDKs receive only a few codes, listed in the Warning below, and get most Permissions errors as plain text without one. Find your client here, then look up the code in the sections below.
On the routes the JavaScript SDKs call, POLICY_DENIED, SPEND_ACCOUNTING_FAILED, INITIATOR_CANNOT_REVIEW and PENDING_TRANSACTION_ALREADY_APPROVED arrive as JSON with a code. So do POLICY_REVIEW_REQUIRED from SDK signing, user is not linked to this app when you sign with an app-owned wallet, APPROVAL_CASES_AFFECTED when a configuration change would invalidate open approval cases, and the decision refusals when an approve or reject is refused. Other Permissions errors on these routes arrive as plain text. For those, error.message holds the server message listed below, error.code is ERR_BAD_REQUEST for a 4xx status or ERR_BAD_RESPONSE for a 5xx status, and error.data is undefined. Match them on error.status and error.message.
The JavaScript SDKs export no class for API errors. SDK calls reject with an error object that carries code and status, plus data when the server returned JSON. The object is not always an Error instance, so check its code property rather than its class. Signing calls are the exception in the web and React SDKs: when the server refuses one, for example with a policy denial, they currently reject with a generic error that has no code. The server SDK and the React Native SDK keep the code, status and data.
The REST and SDK tabs show a policy denial. The CLI does not sign, so its tab shows a policy create that conflicts with an existing draft.

Signing

These errors come from the REST signing endpoints (sign-raw, sign-transaction, sign-message, sign-typed-data, sign-authorization and transfer) and from SDK signing calls. Para evaluates your policies before it signs, so a policy error means nothing was signed.

Review required

When the deciding rule requires approval, a REST signing call returns 403 with POLICY_REVIEW_REQUIRED and does not sign. In the server SDK and the React Native SDK, signing with an app-owned wallet throws the same error, with the fields in error.data. The web and React SDKs currently reject with a generic error that has no data. SDK signing with a user’s wallet works differently: the server returns a pending transaction, and the SDK sends the user to review and waits, or returns the review URL in handoff mode. Those outcomes are listed under SDK error classes.
If a case completed on a user’s own wallet but its approval expired before use, an identical transaction retry can return the same review even without resumeApprovalCaseId. Rebuild the transaction, for example with a fresh fee or nonce, then sign it without resumeApprovalCaseId.
An approval case is tied to its request: the Idempotency-Key, or the request body when you send no key. Once the case can no longer sign that request, every resend returns POLICY_REVIEW_REQUIRED with the same case. That happens when the case is expired, invalidated or cancelled, and when it is completed but was already used to sign or passed its seven-day lifetime. A rejected case returns POLICY_DENIED with review-rejected until its lifetime ends. To start over, resend with a new Idempotency-Key. Case statuses are described in Approval requirements.

Approval cases

These errors come from reading, deciding and cancelling approval cases, for example with getAccessibleApprovalCase, approveApprovalCase, rejectApprovalCase and cancelApprovalCase in the SDKs, or GET /v1/permissions-v2/approval-cases and POST /v1/permissions-v2/approval-cases/{caseId}/cancel on REST. For case statuses and the reasons a case ends, see Approval requirements.
A user named as initiatorUserId can cancel the case with cancelApprovalCase, but cannot read it from the SDK. getAccessibleApprovalCase refuses with INITIATOR_CANNOT_REVIEW, getInitiatedApprovalCase refuses with user did not initiate this approval case, and neither list includes the case. Your backend reads the case with GET /v1/permissions-v2/approval-cases/{caseId} and gives the user its caseId.

Decision refusals

A refused approve or reject returns 403 with the message approval decision is not allowed and one of these codes.
SDK calls receive decision refusals with their code: approveApprovalCase and rejectApprovalCase reject with status: 403 and error.code set to one of the codes below. Read decision from the case before you show approve or reject. It is { canDecide: true, intents } when the user can decide, or { canDecide: false, reason }, where reason is not_eligible, initiator, already_decided, case_terminal or authority_changed.

Approval signatures

These errors apply when an approval requirement collects transaction signatures (evidence: "transaction_signature"), for example with createApprovalSignatureCollection, signApprovalTransaction and getApprovalSignatures. Each signature must come from the user’s own wallet of the collection’s wallet type. createApprovalSignatureCollection opens an approval case, so it can also return the case-opening errors under Review required.

Approval administration

These errors come from managing who can approve: approver assignments, wallet authorization scope bindings and approval configuration. Your backend reaches them on /v1/permissions-v2 REST routes, and configuration managers reach them through updateApprovalConfiguration and resetApprovalConfiguration in the SDKs. Every write takes an expectedRevision and an optional force.

Policy authoring

These errors come from creating, replacing, activating, deactivating and archiving policies with para keys permissions and in the Developer Portal. The Developer Portal shows each error’s message and path next to the JSON. The CLI reports them as described under CLI.
Work through validation errors on your Development key, which runs on beta. A policy reaches Production only after a production review, so request one once the beta policy validates and behaves as expected.
Validation without saving, such as para keys permissions validate, returns 200 with { "valid": false, "errors": [...] } instead of an error. Requesting a production review returns 409 with { "status": "ineligible" } when no Development key has an active policy or the Production key is not awaiting review, and 503 with { "status": "delivery-failed" } when the request could not be delivered.

User parameters

These errors come from reading and saving a user’s adjustable limits: listUserAdjustablePolicies, getUserPolicyParameters, listUserPolicyParameterHistory, updateUserPolicyParameters and resetUserPolicyParameters in the SDKs, and the GET /v1/permissions-v2/users/{userId}/user-parameters routes on REST. SDK calls receive them as plain text.
Saved values belong to one version of a policy. After you publish a new version, each user who saved their own values must confirm them. getUserPolicyParameters returns status: "needs_confirmation" with the earlier values in previousValues, and signing under that policy is denied with parameter_configuration_invalid until the user saves or resets their values. Users who never saved values get the new defaults.
These errors come from reading policies, a user’s spending against a policy and a user’s consent. In the SDKs, that is listPolicies, getPolicy, listApplicablePolicies, getApplicablePolicy, getUserPolicyUsage, listUserPolicyConsents and getUserPolicyConsent. On REST, it is the /v1/permissions-v2/policies, /v1/permissions-v2/users/{userId}/policies/{policyId}/usage, /v1/permissions-v2/wallets/{walletId}/policies/{policyId}/usage and /v1/permissions-v2/users/{userId}/delegation-consents routes. SDK calls receive them as plain text. When Permissions is not enabled for your app, the list reads return empty lists.

Pending transaction review

When a require_approval rule has no approval requirement, POLICY_REVIEW_REQUIRED carries a reviewId. Your backend can approve or reject reviews from REST or standard app-owned SDK signing with your app’s server secret through POST /v1/permissions-v2/reviews/{reviewId}/approve or /reject. Both return 200 with the review’s current status, even when the review has already ended as expired, rejected or consumed. After approved, retry identical SDK signing input without resumeApprovalCaseId only while the approval is unused and unexpired and the request and policy binding still match. Para re-evaluates the request, so approval status alone does not guarantee a signature. The Para Portal handles a user’s own pending transactions.

Idempotency

REST signing identifies a request by its Idempotency-Key, or by the request body when you send no key. Para also uses that identity to tie the request to its approval case. Spend reservations use the Idempotency-Key only.

SDK error classes

The SDKs raise these classes in addition to the server codes above. The review classes come from the JavaScript SDKs when a signing call needs review. The REST SDK also throws ParaRestValidationError before it sends a request, with the message <name> is required, when a required ID or body is empty.

CLI

The CLI receives every error as JSON but prints its own message and exit code. Run with --json to read errorCode, exitCode and details.
create and replace validate the policy before they write it, and report an invalid policy the same way as para keys permissions validate. The CLI prints each error, or { "valid": false, "errors": [...] } with --json, and exits with 10 without an errorCode. details.errors appears with API_VALIDATION_ERROR only when the write or lifecycle call itself is rejected, for example when activate finds that conditional approvals or adjustable parameters are not enabled for your app (permissions_v2_extension_unavailable). For other API errors, including any 403, the CLI prints its own guidance in place of the server message.
Before it calls the API, the CLI can also exit with AUTH_ERROR when you are not logged in (exit 3) or your session has expired (exit 4), and with CONFIG_NO_ORG_AND_PROJECT (exit 9) when no organization and project are selected.

Denial reasons

deniedBy[0].reason explains a POLICY_DENIED response. policyId and ruleId name the deciding rule and are omitted when no rule won. A rule with effect: "require_approval" reports its rule the same way in the reason of POLICY_REVIEW_REQUIRED. So does an allow rule that Para holds for the wallet owner’s review, and Para’s baseline review of a user-owned wallet, which reports matched:para:review-user-owned.
When a rule needs a fact that Para cannot read for a request, the rule’s outcome is unknown. Para denies the request with the fact reason when that rule’s effect outranks the rule that would otherwise decide, or when no other rule matched. It does not fall back to Para’s baseline policies in that case.

Policy validation codes

Policy writes and validation return these codes in errors[].code, each with a path such as $.rules[0].when and a message. A value that does not match the policy schema returns partner_policy_schema_invalid, and a key the schema does not define returns policy_schema_field_unknown. The other codes report problems that the schema alone does not catch. Read path and message together. For the policy format itself, see Policy JSON schema and Facts and conditions.
Leave layer out of policies you write for the CLI or the Developer Portal. Para sets it. A layer other than "partner" fails validation at $.layer: "para" returns policy_layer_owner_mismatch, and any other value returns layer_invalid.

Schema

Schema codes identify unrecognized fields, malformed documents or a missing policy mode.

Selector

Selector codes identify invalid wallet, user, network or app targeting.

Rules

Check these codes for repeated rule IDs, unsupported actions and effects that the ownership model does not allow.

Conditions and facts

These codes cover fact availability, operator and value compatibility, condition structure and metering declarations.

Parameters

Parameter codes cover IDs, default values and where adjustable values can be declared.

Approval requirements

These codes report repeated requirement IDs or features that are not enabled for the app. A minimum_amount setting in safeKnobs can declare a min and max range. If min is above max, or the stage’s minimumAmount falls outside the range, validation returns partner_policy_schema_invalid at $.rules[i].approvalRequirement.safeKnobs[j] with the message minimum configurable amount threshold must not exceed maximum or the published amount threshold must be within the configurable range.

Policy records

These codes come from saving and changing policy records. The conflict codes return 409. The others return 400.