debug-user-tx
Reproduce and debug a user-reported failing transaction against forked cluster state, mapping the failure back to source code
mkdir -p ~/.claude/commands && curl -fsSL https://raw.githubusercontent.com/solanabr/solana-ai-kit/HEAD/.claude/commands/debug-user-tx.md -o ~/.claude/commands/debug-user-tx.mddebug-user-tx.md
You are debugging a transaction that a user reports as failing. You have the project's source code locally; the goal is to reproduce the failure against forked cluster state, then map the on-chain error back to the exact line of Rust / IDL that produced it and suggest a fix.
## Related Skills
- [ext/solana-dev/skill/references/testing.md](../skills/ext/solana-dev/skill/references/testing.md) — Surfpool (mainnet fork), LiteSVM, Mollusk
- [ext/solana-dev/skill/references/programs/anchor.md](../skills/ext/solana-dev/skill/references/programs/anchor.md) — Anchor error codes, constraint failures
- [ext/solana-dev/skill/references/programs/pinocchio.md](../skills/ext/solana-dev/skill/references/programs/pinocchio.md) — Pinocchio error patterns
- [ext/solana-dev/skill/references/security.md](../skills/ext/solana-dev/skill/references/security.md) — Common failure categories
## Inputs
Collect from the user (at least one of `signature` or `instruction` is required):
| Input | Required | Notes |
|-------|----------|-------|
| `signature` | preferred | On-chain tx signature. Fastest path — fetch + replay. |
| `wallet` | optional | User's pubkey. Auto-extracted from tx if signature given. |
| `instruction` | fallback | Raw ix JSON when the tx never landed (serialized tx / accounts + data). |
| `cluster` | optional | `mainnet` / `devnet`. Default: infer from `Anchor.toml` or `.env`. |
| `rpc` | optional | Override RPC endpoint. Default: cluster default or project `.env`. |
| `program` | optional | Program ID. Auto-detected from workspace. |
If the user only pasted an error message, ask for the signature before proceeding — it's the difference between 30 seconds and guessing.
## Step 1: Detect Project Layout
```bash
echo "Detecting project..."
FRAMEWORK="unknown"
if [ -f "Anchor.toml" ]; then
FRAMEWORK="anchor"
echo "Anchor project detected"
elif [ -f "Cargo.toml" ] && grep -q "pinocchio" Cargo.toml 2>/dev/null; then
FRAMEWORK="pinocchio"
echo "Pinocchio project detected"
elif [ -f "Cargo.toml" ] && grep -q "solana-program" Cargo.toml 2>/dev/null; then
FRAMEWORK="native"
echo "Native Solana program detected"
else
echo "No Solana program workspace detected. Debug will proceed RPC-only (no source mapping)."
fi
# Infer cluster
CLUSTER="${CLUSTER:-mainnet}"
if [ -f "Anchor.toml" ]; then
DETECTED=$(grep -m1 'cluster' Anchor.toml | sed 's/.*= *//' | tr -d '"')
[ -n "$DETECTED" ] && CLUSTER="$DETECTED"
fi
echo "Cluster: $CLUSTER"
# Collect program IDs + IDLs
ls target/idl/*.json 2>/dev/null || echo "No IDLs found at target/idl/ — run 'anchor build' for best results"
```
## Step 2: Fetch the Failing Transaction
If a signature was provided, fetch it with full detail. Use the project's RPC if configured; otherwise fall back to the cluster default.
```bash
SIG="<signature>"
RPC="${RPC:-https://api.$CLUSTER.solana.com}"
mkdir -p .claude/debug
OUT=".claude/debug/tx-${SIG:0:8}.json"
curl -s -X POST "$RPC" \
-H "Content-Type: application/json" \
-d "$(cat <<EOF
{
"jsonrpc":"2.0","id":1,"method":"getTransaction",
"params":["$SIG",{"encoding":"json","maxSupportedTransactionVersion":0,"commitment":"confirmed"}]
}
EOF
)" > "$OUT"
# Sanity check
jq -e '.result != null' "$OUT" >/dev/null || { echo "Tx not found or not yet confirmed"; exit 1; }
```
Extract from the JSON (Claude: read `$OUT` with `jq` or the Read tool):
- `meta.err` — the error object (e.g. `{"InstructionError":[1,{"Custom":6003}]}`)
- `meta.logMessages` — full program log output
- `meta.preBalances` / `meta.postBalances`
- `meta.preTokenBalances` / `meta.postTokenBalances`
- `meta.innerInstructions` — CPI tree
- `slot` — for fork replay
- `transaction.message.accountKeys` — ordered account list
- `transaction.message.instructions` — each with `programIdIndex`, `accounts`, `data`
- `transaction.message.addressTableLookups` — resolve if present
## Step 3: Identify the Failing Instruction
From `meta.err`, extract the instruction index. For `InstructionError: [N, ...]`, instruction `N` failed.
```bash
FAILING_IX=$(jq -r '.result.meta.err.InstructionError[0]' "$OUT")
FAILING_PROGRAM=$(jq -r --argjson i "$FAILING_IX" \
'.result.transaction.message.accountKeys[.result.transaction.message.instructions[$i].programIdIndex]' \
"$OUT")
echo "Failing instruction #$FAILING_IX → program $FAILING_PROGRAM"
```
> **Note**: Index 0 is almost always `ComputeBudget` (`setComputeUnitLimit` / `setComputeUnitPrice`). The real failure is usually index ≥ 1. Trust `meta.err.InstructionError[0]`, not position.
> **Address Table Lookups**: If `transaction.message.addressTableLookups` is non-empty, extend the account list before indexing: `accountKeys ++ meta.loadedAddresses.writable ++ meta.loadedAddresses.readonly`. Otherwise you'll resolve the wrong program for CPI-heavy txs.
Compare `$FAILING_PROGRAM` against the project's program IDs (from `declare_id!` or `Anchor.toml`). If it matches, source mapping is possible. If not (e.g. Jupiter, Token Program), the failure is inside a CPI target — note this and proceed with log-based diagnosis.
### Decode the instruction discriminator
`instructions[N].data` is **base58-encoded** when fetched with `encoding: "json"` (what Step 2 uses). Decode before slicing.
For the project's own program:
- **Anchor**: first 8 bytes of decoded data = handler discriminator.
- Anchor ≥ 0.30: match directly against `target/idl/<program>.json` → `instructions[].discriminator`.
- Anchor < 0.30: IDL has no `discriminator` field. Compute it: `sha256("global:<handler_name>")[0..8]`, then match.
- **Pinocchio / native**: typically first 1 byte. Match against the `match` arm in `process_instruction` (grep `src/lib.rs` or `src/entrypoint.rs`).
Record the handler name.
## Step 4: Map the Error to Source
**Fast path — scan `meta.logMessages` first.** Anchor emits one of these formats depending on how the error was raised:
```
# From err!() / return Err(ErrorCode::X.into()) — includes souAnchor framework specialist for rapid Solana program development. Use for building programs with Anchor macros, IDL generation, account validation, and standardized patterns. Prioritizes developer experience while maintaining security.\\n\\nUse when: Building new programs quickly, team projects needing standardization, projects requiring IDL for client generation, or when developer experience is prioritized over maximum CU optimization.
DeFi integration specialist for composing with Solana protocols including Jupiter, Drift, Kamino, Raydium, Orca, Meteora, Marginfi, and Sanctum. Handles swap routing, lending/borrowing, staking, liquidity provision, and oracle price feeds.\n\nUse when: Integrating DeFi protocols, building swap interfaces, implementing lending/borrowing, setting up yield strategies, working with Pyth/Switchboard oracles, or composing multi-protocol transactions.
CI/CD, infrastructure, and deployment specialist for Solana projects. Handles GitHub Actions, Docker, monitoring, RPC management, and Cloudflare Workers edge deployment.\n\nUse when: Setting up CI/CD pipelines, containerizing Solana validators or programs, configuring monitoring and alerting, managing RPC infrastructure, deploying edge workers, or automating build and deploy workflows.
Senior Solana game architect for game system design, Unity/C# architecture, on-chain game state, player progression, NFT integration, and PlaySolana ecosystem. Use for high-level game design decisions, architecture reviews, and planning complex game systems.\n\nUse when: Designing new Solana games from scratch, planning game state on-chain, Unity project architecture, integrating with PlaySolana/PSG1, or deciding between implementation approaches.
React Native and Expo specialist for building Solana mobile dApps. Handles mobile wallet adapter integration, transaction signing UX, deep linking, and mobile-specific performance optimization.\n\nUse when: Building React Native or Expo mobile apps with Solana integration, implementing mobile wallet adapter flows, setting up deep links for transaction signing, or optimizing mobile dApp performance.
CU optimization specialist using Pinocchio framework. Use for performance-critical programs requiring 80-95% CU reduction vs Anchor. Specializes in zero-copy access, manual validation, and minimal binary size.\\n\\nUse when: CU limits are being hit, transaction costs are significant at scale, binary size must be minimized, or maximum throughput is required.
Rust backend specialist for building async services that interact with Solana blockchain. Builds APIs, indexing services, and off-chain processing using Axum, Tokio, and modern async patterns.\n\nUse when: Building REST/WebSocket APIs for Solana dApps, implementing transaction indexers, creating webhook services, or any Rust backend that interacts with Solana.
Senior Solana program architect for system design, account structures, PDA schemes, token economics, and cross-program composability. Use for high-level design decisions, architecture reviews, and planning complex multi-program systems.\n\nUse when: Designing new programs from scratch, planning account structures, optimizing PDA schemes, reviewing architecture for security, or deciding between implementation approaches.