Skip to main content

Error Handling

This guide covers common errors you’ll encounter when integrating with Kroko DEX and how to handle them.

API Errors

When an API call fails, the response includes an error message:
{
  "error": "No route found"
}
ErrorCauseSolution
No route foundNo liquidity path between the tokensVerify token addresses; check that pools exist
Invalid token addressMalformed addressUse checksummed or lowercase hex addresses
Amount must be positiveZero or negative amountProvide a valid positive amount string
Invalid tradeTypetradeType is not 0 or 1Use 0 (Exact Input) or 1 (Exact Output)

Transaction Errors

On-Chain Reverts

These errors occur when the transaction is submitted but reverts on-chain:
ErrorCauseSolution
TRANSFER_FROM_FAILEDInsufficient token approval or balanceCheck Permit2 approval (Steps 1 & 2) and token balance
EXPIREDTransaction deadline exceededUse a longer deadline or resubmit quickly
V3_INVALID_AMOUNT_OUTOutput below minAmountOut (slippage)Increase slippage tolerance or reduce trade size
INSUFFICIENT_ETHNot enough native KAS sent as valueEnsure value matches the required input amount

Wallet Errors

try {
  const tx = await signer.sendTransaction(swapData);
  await tx.wait();
} catch (error) {
  if (error.code === 'ACTION_REJECTED' || error.code === 4001) {
    // User rejected the transaction in their wallet
    console.log('Transaction cancelled by user');
    return;
  }

  if (error.code === 'ERR_NETWORK') {
    // Network connectivity issue
    console.log('Network error — check your connection');
    return;
  }

  // Other errors
  console.error('Transaction failed:', error.message);
}

Approval Errors

Common issues with the approval flow:
SymptomCauseFix
Swap fails after successful approvalApproved wrong contractEnsure Step 1 approves Permit2 (not Universal Router)
Permit2 approval succeeds but swap failsPermit2 sub-approval expiredCheck expiration and re-approve if needed
”Insufficient allowance”Amount approved is less than swap amountApprove MaxUint256 (Step 1) or MaxUint160 (Step 2)

Checking Approval State

// Check ERC-20 → Permit2 approval
const tokenAllowance = await token.allowance(userAddress, PERMIT2);
console.log('Token → Permit2:', tokenAllowance.toString());

// Check Permit2 → Universal Router approval
const [amount, expiration] = await permit2.allowance(
  userAddress, tokenAddress, UNIVERSAL_ROUTER
);
console.log('Permit2 → Router:', amount.toString());
console.log('Expiration:', new Date(Number(expiration) * 1000));

Best Practices

Pre-flight Checks

Before executing a swap, verify:
async function preflightCheck(userAddress, tokenIn, amountIn) {
  // 1. Check balance
  const balance = await token.balanceOf(userAddress);
  if (balance < amountIn) {
    throw new Error(`Insufficient balance: have ${balance}, need ${amountIn}`);
  }

  // 2. Check ERC-20 approval to Permit2
  const allowance = await token.allowance(userAddress, PERMIT2);
  if (allowance < amountIn) {
    return { needsApproval: 'token' };
  }

  // 3. Check Permit2 sub-approval
  const [amount, expiration] = await permit2.allowance(
    userAddress, tokenIn, UNIVERSAL_ROUTER
  );
  if (amount < amountIn || expiration < Math.floor(Date.now() / 1000)) {
    return { needsApproval: 'permit2' };
  }

  return { needsApproval: null };
}

Retry Strategy

  • API errors: Safe to retry immediately (transient network issues)
  • On-chain reverts: Do NOT retry blindly — diagnose the cause first
  • User rejection: Do not retry — wait for user to initiate again
  • Slippage errors: Re-fetch the quote (price may have changed) and retry with fresh calldata