Handle Safe multisig errors
Interpret configuration, coordinator, approval and submission failures and dispose of signing material.
Handle failures and follow best practices. See Need Help for support.
Prerequisites: an initialized account. Keep proposal identifiers when an operation fails so you can inspect its state before trying again.
Handle Failures
| Failure | Response |
|---|---|
ConfigurationError | Check Safe module version, identity options and fee-mode requirements. |
HashMismatchError | Stop signing. Reconcile the coordinator payload with the reviewed proposal/message identifier. |
| Owner validation failure | Verify the selected derivation path and current Safe owner set. |
| Missing proposal/message | Confirm the identifier and coordinator; do not replace a failed lookup with approval. |
| Insufficient confirmations | Collect the required owners' approvals before execution. |
| Paymaster prefund / AA50 failure | Check Safe token funds and paymaster configuration. |
| No receipt after submission | Inspect the existing UserOperation before creating or resubmitting a proposal. |
Import public error classes before using them in handling logic:
import { ConfigurationError, HashMismatchError } from '@tetherto/wdk-wallet-multisig-safe'
import { account, requiredEnv } from './safe-account.mjs'
try {
await account.approveProposal(requiredEnv('PROPOSAL_ID'))
} catch (error) {
if (error instanceof HashMismatchError) {
throw new Error('Coordinator payload differs from the requested proposal', { cause: error })
}
if (error instanceof ConfigurationError) console.error('Check Safe configuration')
throw error
}Beta.1 also throws plain errors and WDK base errors. Do not infer every error class from a message fragment. A bundler response and a successful on-chain receipt are separate states.
Best Practices
Keep native deployment gas, native maximum execution cost and token-denominated estimates separate. The transfer cap is not a universal spending cap.
Use dispose() on the manager when the session ends:
import { wallet } from './safe-account.mjs'
wallet.dispose()Manager disposal clears cached account signing material but retains the manager's seed bytes in beta.1. Release the manager when finished and clear caller-controlled mutable copies after their final use; disposal does not erase every retained copy. Do not log seeds or keyPair. Await toReadOnlyAccount() if you need a query-only account before clearing the signer.