> For the complete documentation index, see [llms.txt](https://docs.elara.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.elara.fi/protocol-reference/reference/error-reference.md).

# Error Reference

Every custom error in the Elara protocol with causes and resolution steps.

## Vault (`IVault`)

### `KycRequired(address account)`

**Cause:** `account` is not approved in `KYCRegistry`. Thrown for both `msg.sender` and `recipient` during `mint` and `redeem`.

**Resolution:** Ensure both the initiating address and the recipient address have been granted KYC via `KYCRegistry.grantKycInBulk`.

***

### `MintDisabled(address token)`

**Cause:** Minting is currently disabled for `token` in `TokenRegistry` (`isMintEnabled = false`).

**Resolution:** Check `TokenRegistry.getTokenConfig(token).isMintEnabled`. An admin can re-enable via `TokenRegistry.toggleMint(token, true)`.

***

### `RedeemDisabled(address token)`

**Cause:** Redemption is currently disabled for `token` in `TokenRegistry` (`isRedeemEnabled = false`).

**Resolution:** Check `TokenRegistry.getTokenConfig(token).isRedeemEnabled`. An admin can re-enable via `TokenRegistry.toggleRedeem(token, true)`.

***

### `InvalidRedemption(uint256 redemptionId)`

**Cause:** No queued redemption exists for `redemptionId`. Either the ID was never created, or the redemption was already settled and deleted.

**Resolution:** Verify the ID from the `RedeemQueued` event. If already settled, check `RedeemSettled` event history.

***

### `InsufficientLiquidity(address token, uint256 required, uint256 available)`

**Cause:** `withdrawWallet` does not have sufficient balance or allowance to cover `required` amount of `token`. Thrown during `settleRedemption` when the treasury still lacks funds.

**Resolution:** Replenish `withdrawWallet` with at least `required` of `token`, and ensure it has approved the Vault for at least that amount. Then retry `settleRedemption`.

***

### `AmountBelowMinimum(uint256 amount, uint256 minimum)`

**Cause:** Zero was passed as `tokenAmount` (mint) or `elUSDAmount` (redeem / yield).

**Resolution:** Pass a non-zero amount.

***

### `InvalidAddress(address provided)`

**Cause:** A zero address was provided where a valid contract address is required (e.g., `treasuryAdapter` not set, zero `recipient`, or `mintYieldToStaking` called by wrong address).

**Resolution:** Ensure all required contract addresses are initialized and non-zero before interacting with the Vault.

***

## TokenRegistry (`ITokenRegistry`)

### `TokenNotSupported(address token)`

**Cause:** `token` is not registered in `TokenRegistry`. Thrown on `updateTokenConfig`, `toggleMint`, `toggleRedeem`, and when the Vault reads config for an unsupported token.

**Resolution:** Register the token via `TokenRegistry.addToken` before using it.

***

### `TokenAlreadySupported(address token)`

**Cause:** Attempted to add a token that is already registered.

**Resolution:** Use `updateTokenConfig` instead of `addToken` to modify an existing token's configuration.

***

### `FeeRateTooHigh(uint256 feeRate, uint256 maxFeeRate)`

**Cause:** `feeRate` exceeds the protocol maximum of **1000 bps (10%)**.

**Resolution:** Use a fee rate between 0 and 1000 bps.

***

### `InvalidDecimals(uint8 decimals)`

**Cause:** `decimals` is 0 or greater than 18.

**Resolution:** Provide a valid decimal count between 1 and 18.

***

### `ArrayLengthMismatch(uint256 length1, uint256 length2)`

**Cause:** The `_initialTokens` and `_initialConfigs` arrays passed to `initialize` have different lengths.

**Resolution:** Ensure both arrays have the same length.

***

### `InvalidAddress(address provided)` *(TokenRegistry)*

**Cause:** Zero address passed as `token` to `addToken`.

**Resolution:** Provide a valid ERC20 token address.

***

## KYCRegistry (`IKYCRegistry`)

### `InvalidAddress(address provided)` *(KYCRegistry)*

**Cause:** A zero address was included in the `addresses` array passed to `grantKycInBulk` or `revokeKycInBulk`.

**Resolution:** Remove zero addresses from the array before calling.

***

### `EmptyArray()`

**Cause:** An empty array was passed to `grantKycInBulk` or `revokeKycInBulk`.

**Resolution:** Provide at least one address.

***

## PriceOracle (`IPriceOracle`)

### `StalePrice(address token, uint256 age, uint256 maxAge)`

**Cause:** The price feed for `token` has not updated within the configured heartbeat window (`age > maxAge`).

**Resolution:** Wait for the feed to publish a fresh round, or widen the heartbeat by reconfiguring the token. Verify the feed publisher is healthy at the source of your configured provider.

***

### `InvalidPrice()`

**Cause:** The configured price feed returned a non-positive answer (`<= 0`), or the external read call reverted (feed down, malformed data, etc.).

**Resolution:** Verify the feed is operational and returning valid data. This error will also occur for any revert from the feed itself.

***

### `FeedNotSet(address token)`

**Cause:** No oracle has been configured for `token` (`oracleTypes[token] == OracleType.NONE`), or the token was deactivated via `deactivateToken`.

**Resolution:** Call the appropriate `configure*` admin function on `PriceOracle` (e.g., `configureChainlink(token, feed, heartbeat)` for `AggregatorV3`-compatible feeds) to register a price source for this token.

***

### `InvalidConfiguration(string reason)`

**Cause:** An unknown `OracleType` was encountered internally. This should not occur in normal operation.

**Resolution:** This is a protocol-level invariant violation. Contact the Elara team.

***

### `InvalidAddress(address provided)` *(PriceOracle)*

**Cause:** Zero address passed as `token` or `feed` when configuring a price source.

**Resolution:** Provide valid non-zero addresses.

***

## ElUSDStake (`IElUSDStake`)

### `ZeroAmount()` *(ElUSDStake)*

**Cause:** Zero was passed to `stake`, `unstake`, or `receiveYield`.

**Resolution:** Pass a non-zero amount.

***

### `InvalidAddress(address provided)` *(ElUSDStake)*

**Cause:** `receiveYield` was called by an address other than the configured Vault, or zero address was passed to `initialize` / `setVaultAddress`.

**Resolution:** Only the authorized Vault contract should call `receiveYield`. Use the correct Vault address.

***

## TreasuryAdapter (`ITreasuryAdapter`)

### `CallerNotVault(address caller)`

**Cause:** `transferIn` or `transferOut` was called by an address other than the configured Vault.

**Resolution:** These functions are Vault-internal. Do not call them directly.

***

### `InsufficientBalance(uint256 available, uint256 required)`

**Cause:** The source address (`from` for `transferIn`, `withdrawWallet` for `transferOut`) does not hold enough tokens.

**Resolution:** Ensure the address holds at least `required` tokens before initiating the operation.

***

### `InsufficientAllowance(address token, uint256 required, uint256 available)`

**Cause:** `withdrawWallet` has not approved the Vault for enough `token` to cover the redemption.

**Resolution:** Have `withdrawWallet` call `IERC20(token).approve(vault, amount)` with sufficient amount.

***

### `ZeroAmount()` *(TreasuryAdapter)*

**Cause:** Zero was passed to `distributeYield`.

**Resolution:** Pass a non-zero yield amount.

***

### `InvalidAddress(address provided)` *(TreasuryAdapter)*

**Cause:** Zero address passed to `initialize` for `depositWallet`/`withdrawWallet`, or to `setVaultAddress`.

**Resolution:** Provide valid non-zero addresses.

***

## ElUSD (`IElUSD`)

### `AccountBlocked(address account)`

**Cause:** `account` is in the `isBlocked` mapping and attempted a transfer.

**Resolution:** The account must be unblocked via `ElUSD.unblockAddresses` by an authorized admin before it can transfer tokens.

***

### `AccountAlreadyBlocked(address account)`

**Cause:** `blockAddresses` was called for an account that is already blocked.

**Resolution:** No action needed — the account is already blocked. Check current state with `ElUSD.isBlocked(account)`.

***

### `AccountNotBlocked(address account)`

**Cause:** `unblockAddresses` was called for an account that is not currently blocked.

**Resolution:** No action needed — the account is already unblocked. Check current state with `ElUSD.isBlocked(account)`.

***

## ElaraBase (`IElaraBase`)

### `InvalidAccessManager()`

**Cause:** A zero address was provided as the `accessManager` during contract initialization.

**Resolution:** Provide a valid, deployed `AccessManager` contract address.
