Here's what I learned in 3 weeks: failed transactions on Solana cost real SOL.
The Surprise
As a backend dev, I'm used to failed requests being free. A 500 error? Retry it. It's no big deal.
Solana is different. When you send a transaction, three things can happen:
- CLI catches it → Free (local balance check)
- Simulation catches it → Free (RPC preflight check)
- On-chain fails → Costs 0.000005 SOL
Watching It Happen
I created a broke wallet (0 SOL) and tried to transfer:
solana transfer --from /tmp/broke-wallet.json $RECIPIENT 1
# Error: insufficient funds (caught locally, free)
Then I used a funded wallet but tried to send more than my balance:
// With skipPreflight = true (dangerous)
await rpc.sendTransaction(tx, { skipPreflight: true });
Result:
Signature: 5NWqdwSCmc3vz2PAwMmBQppL6uogPB7qkRWzUnCFtA9...
Status: Error processing Instruction 0: custom program error: 0x1
Fee: ◎0.000005
Balance: 8.39795 -> 8.397945 SOL
The transaction failed. The fee was still charged.
Why This Matters
In Web2, validation happens before the operation:
if (account.balance >= amount) {
await db.transfer(account, recipient, amount);
}
In Solana, validation happens inside the transaction. The blockchain doesn't check first—it tries to execute and fails if conditions aren't met. The attempt itself is a processed transaction.
The Fix
Always simulate before sending:
// Default: skipPreflight = false (simulates first)
await rpc.sendTransaction(tx, { skipPreflight: false });
And check balances client-side:
const balance = await rpc.getBalance(sender).send();
if (balance.value < amount + fee) {
throw new Error("Insufficient funds");
}
Bottom Line
On Solana, there's no "try it and see." Every attempt that reaches the network costs money. Design your error handling accordingly.
Day 19 of 100 Days of Solana. Full code: [https://github.com/prasiddhnaik/solana-100-days]
Tags: #solana #web3 #blockchain #backend
Top comments (0)