viem-error-parser logoviem-error-parser

Custom ABIs

Register your own contract ABIs to decode custom revert errors.

The decoder ships with a curated set of common ABIs (ERC-20/721/1155, OpenZeppelin Ownable / AccessControl, ERC-2612). To decode your own contract errors, register their ABIs.

With forViem / forWagmi

import { forViem, createAbiEntry } from 'viem-error-parser';
import { myVaultAbi, myStakingAbi } from './abis';

const decoder = forViem({
  abis: [
    createAbiEntry('Vault', myVaultAbi),
    createAbiEntry('Staking', myStakingAbi),
  ],
});

// In your error handler:
const result = decoder.decode(error);
if (result.success) {
  // result.name   -> "InsufficientBalance"
  // result.args   -> { available: 10n, required: 100n }
  // result.source -> "Vault"
}

What createAbiEntry does

createAbiEntry(name, abi) walks the ABI once and pre-computes a Map<Selector, { errorName }>. The result is a stable AbiEntry that the decoder can consult in O(1) per lookup.

Pass the same array reference to forViem / forWagmi / useErrorParser on every render — that is what makes the React hook stable. Define myAbis at module scope, or wrap the array in useMemo with a stable dependency list:

// ✅ Module scope — built once per page load.
const myAbis = [createAbiEntry('Vault', myVaultAbi)];

// ✅ Stable inside a component.
const myAbis = useMemo(
  () => [createAbiEntry('Vault', myVaultAbi)],
  [],
);

// ❌ Re-built on every render — breaks memoisation.
function Bad() {
  const myAbis = [createAbiEntry('Vault', myVaultAbi)];
  // ...
}

Skipping the bundled presets

If you don't want the bundled ERC-20 etc. entries (for example you ship a non-standard token or just want the smallest bundle):

const decoder = forViem({
  includeCommon: false,
  abis: [createAbiEntry('Vault', myVaultAbi)],
});

Conflict resolution

If two ABIs declare an error with the same selector, the first entry wins (insertion order). Bundled common ABIs are added before any abis: you pass, so your overrides — if any — should pass includeCommon: false and re-add the presets after your entries.

On this page