Vesting · Errors · 15@tokenops/sdk/fhe-vesting

Vesting errors you can catch by class.

Catch these by class reference; each carries the offending value (vestingId, unlocksAt, feeType, etc.) so your UI can render a message specific to the failure mode.

For the catch-ladder pattern + how SDK-level and generic-fallback errors fit alongside these, read Concepts › Typed errors + recovery.

ClassWhen thrownRecovery
VestingNotFoundErrorvestingId does not exist on this manager clone.User is likely on the wrong manager. Offer the correct address; the SDK exposes useRecipientVestings to discover their vestings on a manager.
NotVestingRecipientErroruseClaim/usePartialClaim called by an account that is not the schedule's recipient.On the claim revert path err.context carries { method, contractAddress, vestingId } (the contract's NotRecipient is nullary). caller / expectedRecipient are populated by preflightClaim, not this error — read them from a preflight check. Only the recipient can claim; surface 'this vesting belongs to another account' rather than a claim button. useClaim
ClaimLockedErrorThe schedule’s timelock has not elapsed yet (block timestamp < startTimestamp + timelock).err.context.unlocksAt is the Unix timestamp the lock lifts. Render a countdown. useClaim
VestingExpiredErroruseRevokeVesting / useBatchRevokeVesting called on a schedule that has already passed its endTimestamp. Claiming on an ended schedule does not revert.There is nothing left to revoke once a schedule has ended — hide the revoke action after endTimestamp. (Claiming an ended schedule is allowed and pays out any unclaimed vested balance.)
VestingRevokedErrorOperator tried to revoke a vesting that was already revoked, or useSplitVesting was called on an already-revoked source schedule.Read state via useGetVestedAmount / useGetClaimableAmount — both honor revocation. Render 'revoked' instead of a claim button.
VestingNotRevocableErroruseRevokeVesting called on a vesting created with isRevocable=false.Revocability is set at vesting open and immutable. The UI should hide the revoke action unless useVestingInfo(…).data?.isRevocable is true.
TransferAlreadyPendingErroruseInitiateVestingTransfer called while a pending transfer already exists for this vestingId.Check usePendingVestingTransfer first; cancel the prior one before opening a new transfer.
NotPendingRecipientErroruseAcceptVestingTransfer called by an address that is not the pending recipient of the transfer.err.context carries { method, contractAddress, vestingId } here (the contract's NotPendingRecipient is nullary). Only the pending recipient can accept — read usePendingVestingTransfer to surface the address the initiator named. useAcceptVestingTransfer
TransferExpiredErroruseAcceptVestingTransfer called after the transfer's expiry timestamp.err.context carries { method, contractAddress, vestingId } (the contract's TransferExpired is nullary — the mapper does not populate an expiredAt). Read usePendingVestingTransfer for the expiry. An expired offer stays in storage, so re-running useInitiateVestingTransfer reverts TransferAlreadyPending until the current recipient calls useCancelVestingTransfer to clear it — only then can a fresh offer be issued.
NoPendingTransferErroruseCancelVestingTransfer called when no transfer is pending for this vestingId. (useAcceptVestingTransfer with no pending transfer reverts NotPendingRecipient instead — the empty slot's newRecipient is the zero address, which never matches the caller.)err.context carries method, contractAddress, and vestingId. Gate the cancel action on usePendingVestingTransfer returning a pending offer.
AccessDeniedErrorCaller lacks the role the call requires (VESTING_CREATOR_ROLE, REVOKER_ROLE, PAUSER_ROLE, DISCLOSURE_ADMIN_ROLE, …).err.context.role is the bytes32 role identifier. Check useHasRole + the role-constants table on the manager.
BatchTooLargeErroruseBatchCreateVesting passed more entries than the manager allows in a single tx.Chunk the batch. The on-chain cap is encoded in the contract; surface a 'too many entries' UI rather than the raw error.
FeatureDisabledErrorOperator called a feature the manager wasn't configured for (e.g. split on a non-split manager).Configuration flags are immutable at clone-time. Hide the action in the UI if useManagerConfig flags it disabled.
InsufficientBalanceErroruseCreateVesting: encrypted source balance is too low for the requested amount.Re-read the encrypted balance with useDecryptedHandle; surface the cap to the user before they submit.
MissingEncryptorErrorA write hook that encrypts client-side ran without an encryptor injected.Pass encryptor in ManagerHookOptions (parent scope) or via args.encryptor on the mutate call. See /concepts/encryptor.
Each class extends the SDK's base TokenOpsSdkError and carries the offending values under err.context — render specific messages instead of generic "transaction failed."Read the catch ladder