PCL ReasonCodes
Standardized rejection codes PCL emits when a transaction fails policy evaluation. Wallets and middleware key off these to drive UX.
When PCL rejects a transaction, the rejection reason is exposed as a standardized code, not free-form text. This lets wallets, agent SDKs, and dapp UIs interpret the failure consistently and (where appropriate) chain it into an automatic recovery flow — for example, prompting a user to complete KYC when EasAttestationRequired is returned. The codes are stable identifiers; new codes are added when new policy templates are introduced, but existing codes are not renamed or repurposed.
V1 ReasonCode set
| ReasonCode | Meaning | Triggered when |
| :--- | :--- | :--- |
|
|
|
|
|
|
|
|
| :--- | :--- | :--- |
|
InDenylist | Address is on a denylist | Sender or recipient appears in a DENYLIST_POLICY list ||
EasAttestationRequired | Required EAS attestation missing | EAS_POLICY requires a schema the sender does not hold (or attestation is expired/revoked) ||
VolumeAboveMaxLimit | Per-tx amount exceeds max | VOLUME_POLICY max_limit exceeded ||
VolumeBelowMinLimit | Per-tx amount below min | VOLUME_POLICY min_limit not met ||
PeriodicVolumeAboveLimit | Cumulative period limit exceeded | PERIODIC_VOLUME_POLICY or OKRW_EAS_PERIODIC_VOLUME_LIMIT_POLICY window exhausted ||
Unauthorized | Caller lacks permission | Policy-mutation call from an account that isn't the PolicyAdmin (global) or contract admin (per-contract config) ||
PolicyAlreadyRegistered | Duplicate registration | register called for a contract that already has a policy entry ||
UnknownPolicyType | Template not registered | A UnitPolicy.template_id references an enum value that hasn't been registered on this network |How wallets / SDKs should consume these
Treat the ReasonCode as the machine-readable layer. Build your UX off the code, not the human-readable string PCL may also return. For example:
MAWS's
EasAttestationRequired→ trigger your KYC partner's onboarding flow.InDenylist→ terminal rejection; show "this address can't transact" without offering a retry.VolumeAboveMaxLimit/VolumeBelowMinLimit→ suggest splitting the transfer or adjusting the amount.PeriodicVolumeAboveLimit→ show "daily/monthly limit reached; resets at <next window>".Unauthorized/PolicyAlreadyRegistered/UnknownPolicyType→ these are admin-tooling errors; surface as raw error in admin UIs, hide from end-user UIs.
MAWS's
policy.preflight returns the same ReasonCode shape — agents call it before transfer.send to avoid wasting gas on rejected transactions.Adding new codes
When a new
PolicyTemplate is registered (network upgrade), one or more new ReasonCodes are added alongside it. Code identifiers are coined in CamelCase, descriptive of the failure (e.g. a future JurisdictionMismatch would map to a hypothetical jurisdiction-checking template). Old codes never disappear — even if the template they came from is deprecated, the code stays so historic transaction failures remain interpretable.