Explore failed transactions
What happens when things go wrong?
Explore failed transactions
The Scenario
You’ve been sending transactions on devnet and watching them confirm. Everything has gone smoothly, which feels great, but it’s also a little misleading. In production, transactions fail all the time: insufficient funds, expired blockhashes, blown compute budgets, missing signatures. If you’ve ever worked with a REST API, you know that understanding error responses is just as important as handling 200 OK. Today, you’re going to break things on purpose. You’ll intentionally trigger failed transactions, then dissect them to understand exactly what went wrong and why.
The Challenge
What You’ll Need
- Your Day 18 project directory (you’ll add a small script to it in step 4)
- A terminal with the Solana CLI installed
- Your devnet wallet from previous days
- A browser to view Solana Explorer (devnet)
Steps
1. Create a broke wallet
Generate a fresh keypair with zero SOL balance. This wallet has never received an airdrop, so it can’t pay for anything.
solana-keygen new --outfile /tmp/broke-wallet.json --no-bip39-passphrase --force
2. Try to send SOL from an empty wallet
Attempt a transfer using your broke wallet as the fee payer. This will fail because the wallet has no SOL to cover the fee. The CLI catches this locally before the transaction reaches the network.
solana transfer --keypair /tmp/broke-wallet.json $(solana address) 1 --url devnet --allow-unfunded-recipient
You should see an error in the output. Note the error message carefully.
3. Try to send more SOL than you have
Switch back to your funded devnet wallet. Make sure it has some SOL (airdrop if needed), then try to send far more than your balance.
solana airdrop 1 --url devnet
solana transfer $(solana-keygen pubkey /tmp/broke-wallet.json) 500 --url devnet --allow-unfunded-recipient
Your wallet can pay the fee but not the 500 SOL transfer. The CLI shows the same “insufficient funds” error as step 2 because its local check lumps both cases together. Step 4 bypasses that check to show the on-chain difference.
> Note: The devnet airdrop can sometimes fail due to rate limiting. If this happens use the web faucet instead.
4. Capture a failed transaction signature
Some failures happen before the transaction ever reaches the network (the CLI catches them locally). To get a failed transaction that actually lands on-chain, you need to skip preflight simulation. The CLI’s --skip-preflight flag is unreliable for this, so you’ll use a small script in your Day 18 project instead.
Navigate to your Day 18 project.
Create a new file force-fail.mjs with the code in this gist.
Run it:
node force-fail.mjs
Copy the signature from the output.
5. Inspect the failure with the CLI
Use solana confirm -v to get a detailed breakdown of the failed transaction.
solana confirm -v [PASTE_SIGNATURE_HERE] --url devnet
Study the output. You’ll see:
- Status: an error message describing what went wrong
- Fee: the transaction fee that was still charged (yes, failed transactions cost fees)
- Compute Units Consumed: how much compute was used before the failure
- Log Messages: a step-by-step trace from the program that processed the transaction
- Account balances (before and after): notice the fee payer’s balance dropped by the fee amount, even though the transfer didn’t go through
6. View the failure on Solana Explorer
Open your browser and navigate to:
https://explorer.solana.com/tx/[PASTE_SIGNATURE_HERE]?cluster=devnet
The Explorer displays the same information in a visual format: the error, the program logs, the accounts involved, and the balance changes. Compare this view with the CLI output. Notice how the Explorer highlights the failing instruction in red and shows exactly which program returned the error.
7. Stream logs in real time
Open a second terminal and start streaming all transaction logs for your wallet:
solana logs --url devnet
Now go back to your first terminal and trigger another failed transfer. Watch the logs appear in real time in your second terminal. This is similar to tailing server logs while hitting an API endpoint: you see each program invocation, each log line, and the final error as it happens.
What Just Happened
You deliberately broke things, and that’s one of the best ways to learn. In Web2, you’ve probably tested your API error handling by sending malformed requests or hitting endpoints with expired tokens. This is the same idea, but on a blockchain.
A key insight: failed transactions on Solana still cost fees. The network processed your transaction, validators did the work to verify and attempt execution, and they get paid for that work regardless of the outcome. This is fundamentally different from a failed HTTP request, where you don’t get billed per attempt. It means error handling on Solana isn’t just about user experience; it’s about economics. Every failed transaction is real money (even if it’s tiny amounts), so production applications use transaction simulation to catch errors before submitting, saving both time and fees.
You also saw how the meta.err field in a transaction response carries structured error information. Errors like InstructionError tell you which instruction in the transaction failed and why. As you start writing your own programs, these error codes will become your primary debugging tool, similar to reading stack traces in a Web2 application.
Resources
- Solana RPC: getTransaction
- Transaction Confirmation and Expiration Guide
- Retrying Transactions Guide
- Solana CLI Reference
Submission
Take a screenshot showing the output of solana confirm -v for one of your failed transactions, or show the Solana Explorer page for the failed transaction. Submit it to this challenge.