---
title: "Troubleshooting"
url: "/docs/build-on-signet/advanced/troubleshooting/index.md"
description: "Common errors, how to handle them, and debugging tips for Signet development."
---
Common errors and debugging tips for Signet development. Select your language to see relevant code.

## TypeScript

## My transaction reverted If an Ethereum transaction calling Passage or the Transactor reverts, nothing happens on Signet. No tokens are minted, no state changes, no funds stuck in transit.
Check the revert reason:
```typescript try { const hash = await hostWalletClient.writeContract({ ... }); const receipt = await hostPublicClient.waitForTransactionReceipt({ hash }); if (receipt.status === 'reverted') { console.error('Transaction reverted'); } } catch (err) { console.error('Revert reason:', err.shortMessage || err.message); } ``` Common causes: insufficient gas, ERC-20 not approved for the target contract, unsupported token.
## My order isn't getting filled Fillers choose which orders to fill based on profitability. If your order sits unfilled, the spread between input and output is likely too narrow.
```typescript const inputAmount = parseEther('1'); // 1 WETH on Signet const outputAmount = (inputAmount * 995n) / 1000n; // 0.5% to fillers ``` If that's not getting filled, widen to 1% or more. See [pricing guidance](/docs/build-on-signet/transfers/exit-signet/index.md#pricing) .
When the deadline passes, the order expires and the user's tokens remain on Signet. No funds are lost.
## My order submission was rejected The tx-cache rejects orders with invalid Permit2 signatures or already-consumed nonces. Run a feasibility check before submitting:
```typescript import { checkOrderFeasibility } from '@signet-sh/sdk/signing'; const result = await checkOrderFeasibility(signetPublicClient, signedOrder); if (result.issues.length > 0) { for (const issue of result.issues) { console.error(`${issue.type}: need ${issue.required}, have ${issue.available}`); } } ``` Common issues caught by the feasibility check:
insufficient_balance: the user doesn't have enough of the input token insufficient_allowance: Permit2 hasn't been approved for the input token nonce_used: the Permit2 nonce was already consumed by a previous order deadline_expired: the order deadline has already passed ## I can't cancel my order On-chain orders created via initiate cannot be cancelled. The deadline is the only expiry mechanism.
For gasless Permit2-based orders, cancel by consuming the nonce:
```typescript import { isNonceUsed } from '@signet-sh/sdk/signing'; const used = await isNonceUsed(signetPublicClient, userAddress, orderNonce); if (!used) { // Submit any transaction using the same nonce to invalidate the order } ``` ## My bundle wasn't included Check that blockNumber targets a future block:
```typescript const currentBlock = await signetPublicClient.getBlockNumber(); console.log('Current block:', currentBlock, 'Bundle targets:', bundle.blockNumber); // bundle.blockNumber must be > currentBlock ``` Other causes:
The bundle wasn't profitable enough for the builder A non-revertible transaction in the bundle would revert (the entire bundle is dropped). Mark transactions that are allowed to fail with revertingTxHashes. The bundle expired (default TTL is 10 minutes / ~50 blocks) ## Simulation results differ from execution On-chain state can change between simulation and inclusion. Simulate close to submission time:
```typescript import { SignetCallBundleBuilder } from '@signet-sh/sdk/signing'; const simulation = SignetCallBundleBuilder.new() .withTxs(bundle.txs) .withBlockNumber(targetBlock) .withStateBlockNumber('latest') // simulate against current state .build(); ``` Use minTimestamp/maxTimestamp on the bundle to constrain the execution window.
## Unexpected balance values Signet's native asset is USD, not ETH. msg.value, address.balance, and tx.value all denominate in USD with 18 decimals.
```typescript // This returns USD balance, not ETH const balance = await signetPublicClient.getBalance({ address: userAddress }); console.log('USD balance:', formatEther(balance)); ``` See [EVM behavior](/docs/learn-about-signet/evm-behavior/index.md) for all differences from Ethereum.
## Wrong chain or wrong network Parmigiana testnet: rollup chain ID 88888, host chain ID 3151908. Mainnet: rollup 519, host 1.
```typescript const chainId = await signetPublicClient.getChainId(); console.log('Connected to chain:', chainId); // Should be 88888 for Parmigiana rollup ``` ## Permit2 approval missing Gasless orders require a one-time Permit2 approval per input token:
```typescript import { ensurePermit2Approval } from '@signet-sh/sdk/permit2'; const { approved, txHash } = await ensurePermit2Approval( signetWalletClient, signetPublicClient, { token: inputTokenAddress, owner: userAddress, amount: orderAmount } ); ``` The SDK's ensurePermit2Approval checks the current allowance first, handles USDT-style tokens that require resetting to zero, and sets the allowance to maxUint256.
## Receipt call hangs Signet spans two chains. If waitForTransactionReceipt never resolves, the public client is pointed at the wrong one. A receipt call to Signet won't find a transaction sent to Ethereum, and vice versa.
```typescript // Wrong: waiting on Signet for an Ethereum transaction const receipt = await signetPublicClient.waitForTransactionReceipt({ hash: ethTxHash }); // Right: match the client to the chain where the tx was sent const receipt = await hostPublicClient.waitForTransactionReceipt({ hash: ethTxHash }); ``` ## Token not supported Passage supports a fixed set of bridgeable tokens. If a deposit fails, check the supported list on the [Parmigiana quickstart](/docs/build-on-signet/parmigiana/index.md) .
On Parmigiana testnet: ETH, USDC, USDT, and WBTC.

## Rust

## My transaction reverted If an Ethereum transaction calling Passage or the Transactor reverts, nothing happens on Signet. No tokens are minted, no state changes, no funds stuck in transit.
Check the revert reason:
```rust match provider.send_transaction(tx).await { Ok(pending) => { let receipt = pending.get_receipt().await?; if !receipt.status() { eprintln!("Transaction reverted in block {}", receipt.block_number.unwrap()); } } Err(e) => eprintln!("Send failed: {e:?}"), } ``` Common causes: insufficient gas, ERC-20 not approved for the target contract, unsupported token.
## My order isn't getting filled Fillers choose which orders to fill based on profitability. If your order sits unfilled, the spread between input and output is likely too narrow.
```rust let input_amount = U256::from(1_000_000_000_000_000_000u128); // 1 WETH let output_amount = input_amount * U256::from(995) / U256::from(1000); // 0.5% to fillers ``` If that's not getting filled, widen to 1% or more. See [pricing guidance](/docs/build-on-signet/transfers/exit-signet/index.md#pricing) .
When the deadline passes, the order expires and the user's tokens remain on Signet. No funds are lost.
## My order submission was rejected The tx-cache rejects orders with invalid Permit2 signatures or already-consumed nonces.
Common issues:
Insufficient balance: the user doesn't have enough of the input token Insufficient allowance: Permit2 hasn't been approved for the input token Nonce used: the Permit2 nonce was already consumed by a previous order Deadline expired: the order deadline has already passed ## I can't cancel my order On-chain orders created via initiate cannot be cancelled. The deadline is the only expiry mechanism.
For gasless Permit2-based orders, cancel by consuming the nonce:
```rust // Read the nonce bitmap from Permit2 let word_pos = order_nonce / 256; let bit_pos = order_nonce % 256; let bitmap = permit2.nonceBitmap(owner, word_pos).call().await?._0; let is_used = (bitmap >> bit_pos) & U256::from(1) == U256::from(1); ``` ## My bundle wasn't included Check that block_number targets a future block:
```rust let current_block = provider.get_block_number().await?; println!("Current: {}, Target: {}", current_block, bundle.block_number); ``` Other causes:
The bundle wasn't profitable enough for the builder A non-revertible transaction in the bundle would revert (the entire bundle is dropped). Mark transactions that are allowed to fail with reverting_tx_hashes. The bundle expired (default TTL is 10 minutes / ~50 blocks) ## Simulation results differ from execution On-chain state can change between simulation and inclusion. Simulate close to submission time:
```rust use signet_bundle::SignetCallBundle; use alloy::eips::BlockNumberOrTag; let bundle = SignetCallBundle { bundle: EthCallBundle { txs: signed_txs, block_number: target_block, state_block_number: BlockNumberOrTag::Latest, ..Default::default() }, }; let response = provider.client().request("signet_callBundle", (bundle,)).await?; ``` Use min_timestamp/max_timestamp on the bundle to constrain the execution window.
## Unexpected balance values Signet's native asset is USD, not ETH. msg.value, address.balance, and tx.value all denominate in USD with 18 decimals.
```rust // This returns USD balance, not ETH let balance = provider.get_balance(user_address).await?; println!("USD balance: {} wei", balance); ``` See [EVM behavior](/docs/learn-about-signet/evm-behavior/index.md) for all differences from Ethereum.
## Wrong chain or wrong network Parmigiana testnet: rollup chain ID 88888, host chain ID 3151908. Mainnet: rollup 519, host 1.
```rust let chain_id = provider.get_chain_id().await?; println!("Connected to chain: {}", chain_id); // Should be 88888 for Parmigiana rollup ``` ## Permit2 approval missing Gasless orders require a one-time Permit2 approval per input token:
```rust // Approve Permit2 for a token (max allowance) let token = IERC20::new(token_address, &provider); let tx = token.approve(permit2_address, U256::MAX).send().await?; tx.get_receipt().await?; ``` ## Token not supported Passage supports a fixed set of bridgeable tokens. If a deposit fails, check the supported list on the [Parmigiana quickstart](/docs/build-on-signet/parmigiana/index.md) .
On Parmigiana testnet: ETH, USDC, USDT, and WBTC.

## Terminal

## My transaction reverted If an Ethereum transaction calling Passage or the Transactor reverts, nothing happens on Signet. No tokens are minted, no state changes, no funds stuck in transit.
Check the revert reason:
```bash # Check a transaction receipt cast receipt $TX_HASH --rpc-url $HOST_RPC # Decode a revert reason cast run $TX_HASH --rpc-url $HOST_RPC ``` Common causes: insufficient gas, ERC-20 not approved for the target contract, unsupported token.
## My order isn't getting filled Fillers choose which orders to fill based on profitability. If your order sits unfilled, the spread between input and output is likely too narrow. A 0.5% spread (50 basis points) is a reasonable starting point.
If that's not getting filled, widen to 1% or more. See [pricing guidance](/docs/build-on-signet/transfers/exit-signet/index.md#pricing) .
When the deadline passes, the order expires and the user's tokens remain on Signet. No funds are lost.
## My order submission was rejected The tx-cache rejects orders with invalid Permit2 signatures or already-consumed nonces.
Common issues:
Insufficient balance: the user doesn't have enough of the input token Insufficient allowance: Permit2 hasn't been approved for the input token Nonce used: the Permit2 nonce was already consumed by a previous order Deadline expired: the order deadline has already passed ## I can't cancel my order On-chain orders created via initiate cannot be cancelled. The deadline is the only expiry mechanism.
For gasless Permit2-based orders, cancel by consuming the nonce:
```bash # Check if a Permit2 nonce is consumed WORD=$(( $ORDER_NONCE / 256 )) cast call $PERMIT2_ADDRESS \ "nonceBitmap(address,uint256)(uint256)" \ $OWNER_ADDRESS $WORD \ --rpc-url $SIGNET_RPC ``` ## My bundle wasn't included Check that the target block is in the future:
```bash cast block-number --rpc-url $SIGNET_RPC ``` Other causes:
The bundle wasn't profitable enough for the builder A non-revertible transaction in the bundle would revert (the entire bundle is dropped). Mark transactions that are allowed to fail with revertingTxHashes. The bundle expired (default TTL is 10 minutes / ~50 blocks) ## Simulation results differ from execution On-chain state can change between simulation and inclusion. Simulate close to submission time:
```bash cast rpc signet_callBundle \ '{"txs":["0x..."],"blockNumber":"0x...","stateBlockNumber":"latest"}' \ --rpc-url $SIGNET_RPC ``` Use minTimestamp/maxTimestamp on the bundle to constrain the execution window.
## Unexpected balance values Signet's native asset is USD, not ETH. msg.value, address.balance, and tx.value all denominate in USD with 18 decimals.
```bash # This shows USD, not ETH cast balance $YOUR_ADDRESS --rpc-url $SIGNET_RPC ``` See [EVM behavior](/docs/learn-about-signet/evm-behavior/index.md) for all differences from Ethereum.
## Wrong chain or wrong network Parmigiana testnet: rollup chain ID 88888, host chain ID 3151908. Mainnet: rollup 519, host 1.
```bash cast chain-id --rpc-url $SIGNET_RPC # Should return 88888 cast chain-id --rpc-url $HOST_RPC # Should return 3151908 ``` ## Permit2 approval missing Gasless orders require a one-time Permit2 approval per input token:
```bash cast send $TOKEN_ADDRESS \ "approve(address,uint256)" \ $PERMIT2_ADDRESS $(cast max-uint) \ --rpc-url $SIGNET_RPC \ --private-key $PRIVATE_KEY ``` ## Token not supported Passage supports a fixed set of bridgeable tokens. If a deposit fails, check the supported list on the [Parmigiana quickstart](/docs/build-on-signet/parmigiana/index.md) .
On Parmigiana testnet: ETH, USDC, USDT, and WBTC.

