Debug Solana Transaction Simulation
Use simulateTransaction and preflight logs to debug failed Solana transactions before changing routes, signers, or RPC providers.
Debug Solana Transaction Simulation
Simulation is the cheapest place to learn why a Solana transaction will fail.
Use this page when a transaction fails before confirmation, preflight returns logs, or a swap/backend flow is stuck on a vague "simulation failed" message. The goal is not to explain every Solana program error. The goal is to preserve the right evidence, classify the failure, and decide whether to rebuild, retry, or escalate.
For broad submit/confirm flow, use Transaction Lifecycle. For HTTP and JSON-RPC status triage, use RPC Errors Reference.
Part of the Carbium Solana infrastructure stack.
What Simulation Answers
simulateTransaction asks an RPC node to evaluate a signed transaction without submitting it to the cluster. Solana also uses simulation during sendTransaction preflight unless your client disables preflight.
Read simulation as a diagnostic checkpoint:
| Signal | What it tells you |
|---|---|
err | The transaction would fail if submitted in the simulated state |
logs | Program logs and instruction-level clues |
unitsConsumed | Compute used during simulation, when available |
accounts | Optional returned account data if requested |
replacementBlockhash | A newer blockhash suggestion when replacement is requested |
The official Solana RPC docs define these fields for simulateTransaction. The sendTransaction docs also state that preflight verifies signatures and simulates the transaction before submission unless preflight is disabled.
Start With The Failure Boundary
Before changing code, identify where the failure happened.
| Failure boundary | What to inspect first | Usual next page |
|---|---|---|
| Quote request failed | HTTP status, auth header, route response | Swap API Errors Reference |
txn was missing | user_account, request family, route availability | Q1 |
| Simulation failed | err, logs, instruction index, compute hints | This page |
| Blockhash expired | quote age, wallet approval delay, resend policy | Blockhash Expiry Recovery Playbook |
| Signature was submitted but unclear | signature status, duplicate-send policy | Sending Transactions through Carbium RPC |
This distinction prevents a common bad loop: switching RPC providers when the transaction itself is malformed, stale, underfunded, or built for a different account state.
Minimal Simulation Call
Most applications use a Solana client library, but the underlying JSON-RPC call looks like this:
{
"jsonrpc": "2.0",
"id": 1,
"method": "simulateTransaction",
"params": [
"BASE64_SIGNED_TRANSACTION",
{
"encoding": "base64",
"sigVerify": true,
"replaceRecentBlockhash": false,
"commitment": "processed"
}
]
}Use a signed transaction for the most realistic result. If your simulation disables signature verification, do not treat it as proof that the real signed send path is healthy.
When you are relaying through Carbium RPC, point your Solana client at your backend-held RPC endpoint:
https://rpc.carbium.io/?apiKey=YOUR_RPC_KEYKeep the RPC key server-side. Simulation is a debugging tool, not a reason to expose authenticated infrastructure URLs in frontend code.
Read The Error Like A Debugger
When simulation fails, preserve the full response before rebuilding the transaction.
{
"value": {
"err": {
"InstructionError": [2, { "Custom": 6001 }]
},
"logs": [
"Program ... invoke [1]",
"Program log: Slippage tolerance exceeded",
"Program ... failed: custom program error: 0x1771"
],
"unitsConsumed": 94123
}
}The important parts are:
- instruction index: which instruction failed
- program logs: the closest human-readable explanation
- custom error: a program-specific code, not a universal Solana error
- compute usage: whether compute budget may be part of the problem
Do not reduce this to "RPC failed." The RPC node is reporting what the runtime observed during simulation.
Common Patterns And Next Checks
| Simulation pattern | Likely cause | Next check |
|---|---|---|
InstructionError with custom program code | Program-specific rule failed | Read program logs, route metadata, and app assumptions |
| Logs mention slippage or output threshold | Quote is stale or price moved | Requote and compare destAmountOutMin |
| Logs mention missing account or owner mismatch | Wrong token account, ATA, signer, or mint | Verify wallet, token mint, and account derivation |
| Compute budget exceeded | Transaction needs different compute policy | Review compute instructions before send |
| Blockhash not found or too old | Transaction aged out before send | Use the blockhash recovery page |
| Signature verification failure | Payload was not signed as expected | Check signer boundary and serialized transaction handling |
For Carbium Swap API flows, keep quote-stage and send-stage logs separate. A good support record should show the quote parameters, returned route metadata, transaction handoff, simulation response, submitted signature if any, and final confirmation status.
Preflight: Default On, Skip Only Deliberately
sendTransaction can run preflight simulation before submitting the transaction. Leaving preflight on is the safer default for wallets, dashboards, onboarding flows, and support-heavy apps because it catches obvious failures before users or systems wait for confirmation.
Skipping preflight can be reasonable for latency-sensitive backends that already validated the transaction path and accept the tradeoff. Make that a product decision, not a copy-pasted default.
| Use case | Preflight default |
|---|---|
| Wallet or consumer app | Keep preflight on |
| New integration | Keep preflight on until logs are boring |
| Backend executor with strong quote validation | Consider skipping only after measurement |
| Debugging a failure | Run simulation or enable preflight |
If you skip preflight and the send path fails later, you still need equivalent logs somewhere else. Speed without observability usually makes incidents slower, not faster.
Production Logging Checklist
Before a Solana transaction flow goes live, make sure your logs can answer:
- which user or app request created the transaction
- which quote or route response produced the payload
- which wallet or signer signed it
- whether simulation/preflight ran
- what
err,logs, andunitsConsumedsaid - whether a signature was submitted
- what final signature status returned
Redact API keys, authenticated RPC URLs, private keys, and user-sensitive data before sharing logs in support channels.
If simulation says the transaction would fail, rebuild from the cause. If submission already returned a signature, check signature status before creating a new transaction.
Building transaction-heavy Solana flows with Carbium? Keep simulation evidence, quote logs, and signature status together so failures can be fixed instead of guessed.
Updated 1 day ago
