A transaction fails with InsufficientFundsForRent while the wallet clearly has SOL in it. The balance looks fine, the amount being moved looks fine, and the error still fires.
The reason is that part of every account's balance is not spendable. It is a deposit, and Solana enforces it at execution time.
What Rent Exemption Actually Is
Every account on Solana occupies storage, and storage costs the network something. Rather than charging periodically, Solana requires a one-time balance proportional to the account's size. Hold at least that much and the account is rent-exempt — it persists indefinitely.
★The balance is not consumed. It is locked.★ You get it back when the account is closed, which is why closing unused accounts is a real way to recover SOL.
import { NONCE_ACCOUNT_LENGTH } from "@solana/web3.js";
// Never hardcode this — it depends on network parameters.
const rent = await connection.getMinimumBalanceForRentExemption(
NONCE_ACCOUNT_LENGTH,
);
Why the Error Is Confusing
InsufficientFundsForRent does not mean "you have no SOL." It means ★an account would be left below its exemption threshold after this transaction.★
Three ways to trigger it while looking well funded:
Sweeping a wallet. You transfer the full balance out, leaving the account below the minimum for its own size.
const balance = await connection.getBalance(wallet);
// Fails: leaves the account below exemption.
SystemProgram.transfer({ lamports: balance, ... });
// Works: leave the exemption plus the fee.
const minimum = await connection.getMinimumBalanceForRentExemption(0);
const fee = 5_000;
SystemProgram.transfer({ lamports: balance - minimum - fee, ... });
Creating an account without funding it enough. The account is created but immediately below threshold, and the runtime rejects it.
Chained instructions that create accounts. A swap that creates an associated token account needs the exemption for that new account on top of everything else. ★The cost shows up in a transaction you did not think was creating anything.★
What Each Account Type Locks Up
Approximate, since exemption scales with byte size and network parameters:
| Account | Size | Relative cost |
|---|---|---|
| Basic system account | 0 bytes | ★smallest★ |
| Token account (ATA) | 165 bytes | ★small but multiplies★ |
| Nonce account | 80 bytes | small |
| Mint account | 82 bytes | small |
| Program-owned data account | varies | ★scales with size★ |
★Always query rather than hardcode.★ The values are network parameters, and a constant copied from a blog post is a bug waiting for a parameter change.
If your transactions are funded correctly and still not landing, a free BoltTx key is one line to test the routing side against.
Where This Bites a Trading Bot
The individual amounts are small. The pattern is what costs you.
★Every distinct token a wallet holds needs its own token account, each rent-exempt.★ A bot trading memecoins accumulates one per token, and those balances stay locked until the accounts are closed.
Trade 200 different tokens over a month
→ up to 200 token accounts
→ ★200 × exemption, locked★
→ most holding dust from tokens you exited
None of it is lost — but it is working capital sitting in accounts you no longer use. For a bot running on a fixed balance, this is capital that could have been in positions.
Reclaiming It
Empty token accounts can be closed, returning the exemption to you:
import { createCloseAccountInstruction } from "@solana/spl-token";
// Only works on a zero-balance account. Burn or transfer dust first.
const ix = createCloseAccountInstruction(
tokenAccount,
destination, // where the reclaimed lamports go
owner,
);
★A cleanup routine is worth writing once.★ Scan for zero-balance token accounts, batch the close instructions, and recover the locked SOL. Bots that trade many tokens accumulate these continuously.
Two cautions:
Close only zero-balance accounts. Closing an account with tokens in it burns them. Check the balance in the same transaction rather than relying on a stale read.
Batch, but respect transaction size. Each close instruction adds bytes. A transaction that grows past the size limit fails outright, so chunk conservatively rather than packing to the edge.
Rent and Transaction Failure
The connection to landing is direct, and it is a failure mode most people meet the hard way.
★A transaction that creates an account needs the exemption available at execution time, not at signing time.★ If your balance dropped between building and landing — because another of your transactions landed first — the account creation fails.
For a bot sending concurrently against one wallet, this is a real race:
tx A: swap, creates ATA, needs exemption
tx B: swap, creates ATA, needs exemption
→ ★both signed against a balance that only covers one★
→ whichever lands second fails
The fix is reserving headroom rather than computing against your exact current balance. ★Treat some portion of the wallet as unavailable, sized to your concurrency.★
Checking Before You Send
async function canAffordAccountCreation(
connection: Connection,
payer: PublicKey,
accountSize: number,
concurrentTxs: number,
): Promise<boolean> {
const balance = await connection.getBalance(payer);
const rent = await connection.getMinimumBalanceForRentExemption(accountSize);
const payerMinimum = await connection.getMinimumBalanceForRentExemption(0);
const feeBuffer = 5_000 * concurrentTxs;
// Headroom for every in-flight transaction, not just this one.
return balance >= payerMinimum + rent * concurrentTxs + feeBuffer;
}
What Landing Looks Like
Real transactions through our delivery nodes: median confirmation 336ms — under one slot.
★Rent failures happen at execution, which means the transaction reached a block and consumed a base fee.★ That makes them more expensive than transactions that never land, and worth preventing rather than retrying.
Where BoltTx Fits
We handle submission. Rent is a property of your transaction, decided before it reaches us.
Submissions route through our own delivery nodes in four regions with stake-weighted routing and no public mempool exposure, so a transaction is not observable in transit before it lands. You sign locally — we never hold funds, never sign, and never modify transaction contents.
The tip travels inside the transaction, paid on chain from your own wallet, and reverts with the transaction if it fails, because that is how Solana handles atomic transactions. You pay only on transactions that reach the chain.
Get a free API key. No monthly fee:
const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");
FAQ
What is rent exemption on Solana? A minimum balance proportional to an account's size that lets it persist indefinitely. It is locked rather than spent, and returned when the account is closed.
Why do I get InsufficientFundsForRent when I have SOL? Because the transaction would leave an account below its exemption threshold. Usually you are sweeping a full balance, or creating an account without funding it to the minimum.
How much SOL does a token account lock up?
A token account is 165 bytes, and the exemption scales with size. Query getMinimumBalanceForRentExemption(165) rather than hardcoding, since it depends on network parameters.
Can I get rent-exempt SOL back?
Yes, by closing the account. For token accounts, createCloseAccountInstruction returns the locked lamports, but only on a zero-balance account — closing one with tokens in it burns them.
How do I transfer my entire SOL balance?
You cannot transfer all of it. Leave the exemption for a zero-byte account plus the transaction fee, or the transfer fails with InsufficientFundsForRent.
Why did my swap fail with a rent error? The swap likely created an associated token account for a mint you had not held before. That creation needs the exemption on top of the swap amount and fees, in the same transaction.
Do I need to pay rent periodically? No. Solana replaced periodic rent collection with the exemption model. Hold the minimum for your account size and it persists without further charges.
How many token accounts does a trading bot accumulate? One per distinct mint it has held. A bot trading many memecoins can accumulate hundreds, each locking its exemption until closed. Most end up holding dust from exited positions.
Should I close empty token accounts? Yes, if you trade many tokens. Each closure returns the locked exemption. A periodic cleanup routine that scans for zero-balance accounts and batches the closes recovers meaningful capital.
Can I close a token account with tokens still in it? The instruction will burn them. Transfer or burn the remainder first, and check the balance in the same transaction rather than relying on a read that may be stale.
How many close instructions fit in one transaction? Enough to batch usefully, but each adds bytes and a transaction that exceeds the size limit fails outright. Chunk conservatively rather than packing to the edge.
Why does rent cause failures under concurrency? Because exemption is checked at execution, not at signing. Two concurrent transactions each creating an account can both be signed against a balance that only covers one — whichever lands second fails.
How much headroom should I leave in a bot wallet? Enough for the exemptions of every account your in-flight transactions might create, plus fees for all of them. Sizing to your exact current balance is what produces the concurrency race.
Does rent exemption change over time?
The rate is a network parameter, so hardcoded values can go stale. Always query getMinimumBalanceForRentExemption for the size you need.
Is rent exemption the same for every account? No, it scales with byte size. A zero-byte system account needs the least; a token account at 165 bytes needs more; large program data accounts need substantially more.
What is the difference between rent and transaction fees? Fees are consumed and gone. Rent exemption is locked and recoverable when the account is closed. One is a cost, the other is a deposit.
Related Reading
- Solana Associated Token Accounts
- Solana Transaction Error Codes
- Debugging Failed Solana Transactions
- Solana Durable Nonce Guide
- Solana Transaction Landing