Skip to content

Instantly share code, notes, and snippets.

@jeanregisser
Last active March 30, 2026 17:49
Show Gist options
  • Select an option

  • Save jeanregisser/4103cef8ccaf8d18e05b9e33ae403dbe to your computer and use it in GitHub Desktop.

Select an option

Save jeanregisser/4103cef8ccaf8d18e05b9e33ae403dbe to your computer and use it in GitHub Desktop.
Viem's error messages — inspiration for Crypto Onramp SDK KYC errors

Viem's Error Messages — Inspiration for Crypto Onramp SDK

TL;DR: Errors are a UI. Viem (Ethereum TypeScript library) sets the bar for developer-facing errors. Here's a real viem error when a contract call reverts — notice how every field helps you debug:

The contract function "transfer" reverted with the following reason:
Internal error

Contract Call:
  address:   0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
  function:  transfer(address to, uint256 amount)
  args:              (0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045, 1000000)
  sender:    0x0000000000000000000000000000000000000001

Docs: https://viem.sh/docs/contract/simulateContract
Details: Internal error
Version: viem@2.47.6

Human-readable reason, structured call context, docs link, version tag. Now imagine the same for our KYC flow:

KYC verification for session "cos_abc123" was rejected.

Reason: document_expired

- Identity document must not be expired at time of submission.
- Document expiration date detected: 2024-01-15.
- Resubmit with a valid, non-expired government-issued photo ID.

Verification attempt:
  session:   cos_abc123
  user:      usr_xyz789
  doc_type:  passport
  submitted: 2026-03-28T14:32:00Z

Next step: Call `createVerificationSession()` to start a new attempt.
Docs: https://docs.stripe.com/crypto/onramp/kyc-verification
SDK: @stripe/crypto-onramp@1.2.3

Runnable viem examples + full pattern breakdown below.

Run the demo

npm install viem
node demo.mjs

What viem errors look like in practice

Validation error (invalid address)

Address "0xdeadbeef" is invalid.

- Address must be a hex value of 20 bytes (40 hex characters).
- Address must match its checksum counterpart.

Version: viem@2.47.6

ABI decoding error (corrupt return data)

Data size of 2 bytes is too small for given parameters.

Params: (uint256)
Data:   0x1234 (2 bytes)

Version: viem@2.47.6

Contract call revert (ERC20 transfer with no balance)

The contract function "transfer" reverted with the following reason:
Internal error

Contract Call:
  address:   0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
  function:  transfer(address to, uint256 amount)
  args:              (0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045, 1000000)
  sender:    0x0000000000000000000000000000000000000001

Docs: https://viem.sh/docs/contract/simulateContract
Details: Internal error
Version: viem@2.47.6

The patterns

Pattern What viem does Why it works
Echo the input Address "0xdeadbeef" is invalid No guessing which param failed
List the rules Must be 20 bytes, must match checksum Developer knows how to fix it without Googling
Structured context Formatted block with address, function, args, sender Copy-pasteable into a debugger
Docs link Docs: https://viem.sh/docs/contract/simulateContract Zero-friction path to help
Version tag Version: viem@2.47.6 Instant triage on bug reports
Human-readable names "transfer" reverted not 0xa9059cbb reverted Raw data still in Details: if needed

Applying this to Crypto Onramp KYC errors

The validation error pattern is the closest fit for KYC — see the example at the top.

viem pattern Onramp SDK equivalent
Echo the bad value Echo rejection reason + detected issue (e.g. expiry date)
List the rules What's required to pass (accepted doc types, validity requirements)
Docs link Link to specific KYC doc page, not generic API reference
Structured context Session ID, state, relevant params
Version tag SDK version
Next step (addition) The concrete API call to recover — don't make devs guess
import {
createPublicClient,
http,
encodeFunctionData,
decodeFunctionResult,
getAddress,
parseAbi,
parseEther,
} from "viem";
import { mainnet } from "viem/chains";
// Helper to run each example and capture the error
async function showError(label, fn) {
console.log(`\n${"=".repeat(70)}`);
console.log(` EXAMPLE: ${label}`);
console.log(`${"=".repeat(70)}\n`);
try {
await fn();
} catch (e) {
console.log(e.message);
}
}
const client = createPublicClient({
chain: mainnet,
transport: http("https://cloudflare-eth.com"),
});
// ── 1. Invalid address ───────────────────────────────────────────────
await showError("Invalid address (too short)", () => {
getAddress("0xdeadbeef");
});
// ── 2. ABI encoding: wrong argument type ─────────────────────────────
await showError("ABI encoding: passing a non-address string", () => {
encodeFunctionData({
abi: parseAbi(["function transfer(address to, uint256 amount)"]),
functionName: "transfer",
args: ["not-an-address", 100n],
});
});
// ── 3. ABI decoding: corrupt/truncated return data ───────────────────
await showError("ABI decoding: return data too short", () => {
decodeFunctionResult({
abi: parseAbi(["function balanceOf(address) returns (uint256)"]),
functionName: "balanceOf",
data: "0x1234",
});
});
// ── 4. Contract revert: ERC20 transfer with no balance ───────────────
await showError(
"Contract revert: USDC transfer from account with zero balance",
async () => {
await client.simulateContract({
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC proxy
abi: parseAbi([
"function transfer(address to, uint256 amount) returns (bool)",
]),
functionName: "transfer",
args: ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", 1_000_000n], // 1 USDC
account: "0x0000000000000000000000000000000000000001", // no USDC
});
}
);
// ── 5. Read contract: call a function that doesn't exist ─────────────
await showError(
"Contract read: calling a function that doesn't exist on the contract",
async () => {
await client.readContract({
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
abi: parseAbi(["function fooBar() returns (uint256)"]),
functionName: "fooBar",
});
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment