> ## Documentation Index
> Fetch the complete documentation index at: https://base-a060aa97-roethke-b20-upgrade-pages.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Custom B20 errors, selectors, and the conditions that trigger them.

*Exhaustive list of custom errors, selectors, and the conditions that trigger them. Selectors are the 4-byte `keccak256` hash of the error signature — computed with `cast sig "ErrorName(types...)"`. Enum parameters encode as their underlying `uint8`.*

*Note: several error names are reused across files with different parameters (or none), which changes the selector. `PolicyNotFound()` ([`IPolicyRegistry`](/specifications/b20/reference/interfaces/i-policy-registry)) and `PolicyNotFound(uint64)` ([`IB20`](/specifications/b20/reference/interfaces/ib20)) are unrelated errors with different selectors, as are `Unauthorized()` (`IB20` / `IPolicyRegistry`) and `Unauthorized(address)` ([`IActivationRegistry`](/specifications/b20/reference/interfaces/i-activation-registry)). Conversely, `LengthMismatch(uint256,uint256)` shares one selector across [`IB20Asset`](/specifications/b20/reference/interfaces/ib20-asset) and [`B20FactoryLib`](https://github.com/base/base-std/blob/main/src/lib/B20FactoryLib.sol) — they're independently declared but identical in signature.*

## [`IB20`](/specifications/b20/reference/interfaces/ib20)

| Error | Selector | Thrown when |
| - | - | - |
| `NonPayable()` | `0x6fb1b0e9` | ETH was attached to a call targeting a nonpayable token selector. |
| `AccessControlUnauthorizedAccount(address account, bytes32 neededRole)` | `0xe2517d3f` | `account` does not hold `neededRole`. |
| `Unauthorized()` | `0x82b42900` | Caller failed a positional authorization check that isn't expressible as "missing role X". |
| `ContractPaused(uint8 feature)` | `0xfd8c4245` | The `PausableFeature` covering the operation is currently paused. |
| `InsufficientAllowance(address spender, uint256 allowance, uint256 needed)` | `0x192b9e4e` | `spender`'s allowance is less than `needed` for the requested `transferFrom`. |
| `InsufficientBalance(address sender, uint256 balance, uint256 needed)` | `0xdb42144d` | `sender`'s balance is less than `needed` for the requested transfer or burn. |
| `InvalidSender(address sender)` | `0x4c14f64c` | The transfer's source address is invalid (typically `address(0)`). |
| `InvalidReceiver(address receiver)` | `0x9cfea583` | The transfer's destination address is invalid (`address(0)`, or any B20-prefix address). |
| `InvalidApprover(address approver)` | `0x8bc146c4` | The approval's `owner` address is invalid (typically `address(0)`). |
| `InvalidSpender(address spender)` | `0x4e15efda` | The approval's `spender` address is invalid (typically `address(0)`). |
| `InvalidAmount()` | `0x2c5211c6` | An amount argument was zero where a non-zero value is required. Not used for ERC-20 amount arguments. |
| `EmptyFeatureSet()` | `0x4861ff45` | An empty array was passed to a function that requires at least one element. |
| `InvalidSupplyCap(uint256 currentSupply, uint256 proposedCap)` | `0x0a3780ce` | The proposed supply cap is below the current `totalSupply`, or above `type(uint128).max`. |
| `SupplyCapExceeded(uint256 cap, uint256 attempted)` | `0x4b344b11` | The mint would push `totalSupply` past the configured cap. |
| `PolicyForbids(bytes32 policyScope, uint64 policyId)` | `0xa43fec12` | A policy slot denied the operation. |
| `PolicyNotFound(uint64 policyId)` | `0xcccad523` | The provided policy ID does not exist in the policy registry. |
| `UnsupportedPolicyType(bytes32 policyScope)` | `0xcdd98a4a` | `policyScope` is not a slot this token (or its variant) supports. |
| `AccountNotSeizable(address account)` | `0x91dbbc8d` | `seizeWithMemo` was called against a `from` that is seize-exempt (still authorized) under `SEIZE_EXEMPT_POLICY`. |
| `AccountNotBlocked(address account)` | `0x64a5cb46` | The deprecated `burnBlocked` was called against a `from` that is currently authorized under `TRANSFER_SENDER_POLICY` (i.e. not blocked). |
| `ExpiredSignature(uint256 deadline)` | `0xbd2a913c` | An EIP-2612 `permit` was submitted with a `deadline` strictly less than `block.timestamp`. |
| `InvalidSigner(address signer, address owner)` | `0x7ba5ffb5` | ECDSA recovery on an EIP-2612 `permit` returned `signer`, which does not match the claimed `owner`. |
| `LastAdminCannotRenounce()` | `0x361513e7` | `renounceRole(DEFAULT_ADMIN_ROLE, ...)` was called by the sole remaining admin. |
| `NotSoleAdmin()` | `0x2a98e73b` | `renounceLastAdmin()` was called when other accounts also hold `DEFAULT_ADMIN_ROLE`. |
| `AccessControlBadConfirmation()` | `0x6697b232` | The `callerConfirmation` argument to `renounceRole` was not `msg.sender`. |

## [`IB20Asset`](/specifications/b20/reference/interfaces/ib20-asset)

| Error | Selector | Thrown when |
| - | - | - |
| `AnnouncementIdAlreadyUsed(string id)` | `0xd10b3c9e` | `announce` was called with an `id` that has already been consumed. |
| `InvalidMetadataKey()` | `0x86ea3abb` | `updateExtraMetadata` was called with an empty `key`. |
| `InvalidMultiplier()` | `0x6f12f3dc` | A multiplier setter (`updateUIMultiplier` or the deprecated `updateMultiplier`) was called with a multiplier of zero or above the `type(uint128).max` overflow guard. |
| `EffectiveAtInPast(uint256 effectiveAt)` | `0x14119cf6` | `updateUIMultiplier` was called with an `effectiveAt` that is not in the future. |
| `EffectiveAtTooFar(uint256 effectiveAt)` | `0x1ce214fa` | `updateUIMultiplier` was called with an `effectiveAt` above `type(uint64).max`. |
| `UIMultiplierUpdateExists(uint256 effectiveAt)` | `0x4481a68e` | `updateUIMultiplier` was called while a live pending update already exists. |
| `UIMultiplierUpdateDoesNotExist()` | `0xa7d6a5ca` | `cancelUIMultiplierUpdate` was called when there is no live pending update. |
| `LengthMismatch(uint256 leftLen, uint256 rightLen)` | `0xab8b67c6` | A batched function was called with parallel arrays of differing lengths. |
| `EmptyBatch()` | `0xc2e5347d` | A batched function was called with empty arrays. |
| `AnnouncementInProgress()` | `0x5c5f0829` | An inner call dispatched by `announce` tried to re-invoke `announce`. |
| `InternalCallMalformed(bytes call)` | `0x4e2f143e` | An inner call dispatched by `announce` was shorter than four bytes. |
| `InternalCallFailed(bytes call)` | `0xb288a127` | An inner call dispatched by `announce` reverted with an ordinary revert (reason not bubbled). |

## [`IB20Factory`](/specifications/b20/reference/interfaces/ib20-factory)

| Error | Selector | Thrown when |
| - | - | - |
| `NonPayable()` | `0x6fb1b0e9` | ETH was attached to a call targeting a nonpayable factory selector. |
| `TokenAlreadyExists(address token)` | `0x15ef3a57` | A token already exists at the deterministic address derived from `(variant, msg.sender, salt)`. |
| `InvalidVariant()` | `0xf10e8e43` | `variant` is not a recognized `B20Variant`. |
| `UnsupportedVersion(uint8 version, uint8 variant)` | `0xc0d8b4e0` | The leading `version` byte in `params` does not match any known encoding for the requested variant. |
| `MissingRequiredField(string field)` | `0x4a43ae87` | A required string argument was the empty string. |
| `InvalidCurrency(string code)` | `0x997c1de8` | The stablecoin `currency` was non-empty but contained a non-`A`-`Z` byte. |
| `InvalidDecimals(uint8 decimals)` | `0xca950391` | The asset `decimals` was outside `[B20Constants.MIN_ASSET_DECIMALS, B20Constants.MAX_ASSET_DECIMALS]`. |
| `InitCallFailed(uint256 index)` | `0x4eae0860` | One of the `initCalls` reverted with no bubbled reason. |

## [`IPolicyRegistry`](/specifications/b20/reference/interfaces/i-policy-registry)

| Error | Selector | Thrown when |
| - | - | - |
| `NonPayable()` | `0x6fb1b0e9` | ETH was attached to a call targeting a nonpayable policy registry selector. |
| `Unauthorized()` | `0x82b42900` | Caller is not the admin required by the attempted operation. |
| `PolicyNotFound()` | `0x720caa4f` | The referenced policy ID does not exist. |
| `IncompatiblePolicyType()` | `0xf1011ef5` | The operation is incompatible with the policy's type. |
| `ZeroAddress()` | `0xd92e233d` | A required address argument was the zero address. |
| `BatchSizeTooLarge(uint256 maxBatchSize)` | `0x083e2f67` | A membership batch exceeded the registry limit. |
| `NoPendingAdmin()` | `0xb4539afa` | `finalizeUpdateAdmin` was called with no pending admin staged. |
| `ChildPoliciesOutsideOfRange()` | `0x697ec868` | A composite policy was created or updated with a child-policy count outside `[MIN_COMPOSITE_CHILD_POLICIES, MAX_COMPOSITE_CHILD_POLICIES]`. |
| `InvalidChildPolicy(uint64 childPolicyId)` | `0x46508ef6` | A child policy is not an existing simple (ALLOWLIST/BLOCKLIST) policy. |

## [`IActivationRegistry`](/specifications/b20/reference/interfaces/i-activation-registry)

| Error | Selector | Thrown when |
| - | - | - |
| `Unauthorized(address caller)` | `0x8e4a23d6` | Caller is not the activation admin. |
| `AlreadyActivated(bytes32 feature)` | `0x866b0041` | `activate` was called on a feature that is already activated. |
| `FeatureNotActivated(bytes32 feature)` | `0xb9b2a425` | `checkActivated` was called on an inactive feature, or `deactivate` was called on a feature that is already inactive. |
| `DelegateCallNotAllowed()` | `0x0d89438e` | The precompile was invoked via `DELEGATECALL` or `CALLCODE`. |
| `StaticCallNotAllowed()` | `0xbeaba5b7` | A state-mutating entry point was invoked from a `STATICCALL` frame. |

## [`B20FactoryLib`](https://github.com/base/base-std/blob/main/src/lib/B20FactoryLib.sol)

| Error | Selector | Thrown when |
| - | - | - |
| `LengthMismatch(uint256 leftLen, uint256 rightLen)` | `0xab8b67c6` | Two parallel arrays passed to a `build*` helper had different lengths. |
