Why does Solana say "insufficient funds for rent"? · Jumpstart Blockchain
Why does Solana say "insufficient funds for rent"?
Some account would end the transaction with more than zero lamports but less than its rent-exempt minimum. Find it by index, then fund it fully, sweep it to zero, or fund your reallocs.
Transaction simulation failed: Transaction results in an account (1) with insufficient funds for rent
This error confuses people because the sender usually has plenty of SOL. The problem isn't whether you can afford the transaction. It's the balance some account would be left with after the transaction runs.
What rent means on Solana today
Every account stores data on validators, and Solana charges for that storage through rent. In practice, new accounts must be rent-exempt: they must hold at least a minimum lamport balance that depends on how many bytes of data they store. An account with zero data (a plain wallet) still has a minimum, because every account has fixed overhead.
The rule the runtime enforces after each transaction is, in practice:
An account must end the transaction either with zero lamports (it's closed) or with at least the rent-exempt minimum for its size. Anything in between fails.
The number in parentheses is the index of the offending account in the transaction's account list, not an amount. Index 0 is usually the fee payer.
Don't hard-code the minimum. Ask the cluster for it:
Fetch the blockhash at confirmed commitment right before signing, add a priority fee, and rebroadcast the same signed bytes until confirmed or past lastValidBlockHeight; only then re-sign.
// VersionedTransaction (static keys only; lookup-table keys come after these)
console
log
message
staticAccountKeys
1
toBase58
Then match it to one of the causes below.
Cause 1: sending a small amount to a new address
You transfer 0.0001 SOL to an address that has never held SOL. After the transfer, that account would exist with a balance below the rent-exempt minimum for a zero-data account, so the transaction fails. The recipient is the flagged account.
Fix: the first transfer to a brand-new address must be at least the minimum from getMinimumBalanceForRentExemption(0). If your app sends small payouts, check getBalance(recipient) first and handle the empty-account case explicitly.
Cause 2: draining a wallet, but not completely
You send "everything minus a bit for fees" and leave a few thousand lamports behind. The sender now has a balance above zero and below the minimum. The flagged account is the sender (often index 0, the fee payer).
Fix: either leave at least the rent-exempt minimum, or send exactly balance minus fee so the account ends at zero:
import { SystemProgram, Transaction, PublicKey, Keypair, Connection } from"@solana/web3.js";
asyncfunctionbuildSweep(connection: Connection, from: Keypair, to: PublicKey) {
const balance = await connection.getBalance(from.publicKey, "confirmed");
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
const tx = newTransaction({ feePayer: from.publicKey, blockhash, lastValidBlockHeight });
tx.add(SystemProgram.transfer({ fromPubkey: from.publicKey, toPubkey: to, lamports: balance }));
const fee = (await connection.getFeeForMessage(tx.compileMessage(), "confirmed")).value;
if (fee === null) thrownewError("Could not estimate fee");
// rebuild with the exact amount so the sender ends at 0 lamportsconst sweep = newTransaction({ feePayer: from.publicKey, blockhash, lastValidBlockHeight });
sweep.add(SystemProgram.transfer({ fromPubkey: from.publicKey, toPubkey: to, lamports: balance - fee }));
return sweep;
}
If you add a priority fee instruction, include it before estimating so the fee is correct. The same recipient rule from Cause 1 still applies.
Cause 3: your program grew an account without topping it up
If an on-chain program increases an account's data size, the rent-exempt minimum goes up with it. If nobody transfers the difference in, the account is now under-funded and the transaction fails with this error, flagging that data account.
In Anchor, let the realloc constraint handle the lamports:
Anchor computes the new rent-exempt minimum, transfers the shortfall from payer (or refunds the excess to it when shrinking), and resizes the account. In a native program, do the same by hand: compute Rent::get()?.minimum_balance(new_len), transfer the difference from a payer via the System Program, then resize.
Cause 4: partially draining a program-owned account
A program moves lamports out of a PDA, for example paying out fees it collected, and leaves it below the minimum for its size. Either keep the minimum in the account, or close it properly. In Anchor:
#[account(mut, close = receiver)]pub vault: Account<'info, Vault>,
#[account(mut)]pub receiver: SystemAccount<'info>,
close moves all lamports to receiver and marks the account closed, so it ends at zero and passes the check.
Don't confuse it with "insufficient lamports"
A similar-looking failure has a different cause:
Transfer: insufficient lamports 1000000, need 2039280
Program 11111111111111111111111111111111 failed: custom program error: 0x1
That comes from the System Program itself: the payer doesn't have enough SOL to fund a transfer or an account creation (creating a token account, init in Anchor). The fix is to fund the payer. "Insufficient funds for rent", by contrast, means the transaction would have succeeded but left some account in an invalid in-between balance.
Checklist
Read the index in the error and map it to an address.
Recipient flagged: the first deposit to a new account must be at least the rent-exempt minimum.
Sender or fee payer flagged: leave at least the minimum, or sweep to exactly zero.
Program data account flagged: fund reallocations (realloc::payer in Anchor) and close accounts with close = instead of partial withdrawals.
Always get the minimum from getMinimumBalanceForRentExemption (or Rent::get() on-chain), never from a hard-coded number.