nautechsystems/nautilus_trader · error

ERC-20 approve returned false for token {token}

Error message

ERC-20 approve returned false for token {token}

What it means

Before signing an ERC-20 approve, the client simulates the call and checks its boolean return value. ERC-20 approve returns false on failure in some token implementations; if the simulation succeeds but returns false, the approval will not take effect, so the client bails instead of signing a no-op approval.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:2665

                            &approve_call,
                            block,
                            |result| {
                                if result.is_empty() {
                                    Ok(true)
                                } else {
                                    ERC20::approveCall::abi_decode_returns_validate(result)
                                        .map_err(Into::into)
                                }
                            },
                        )
                        .await,
                    "pre-sign approval simulation",
                )?;

                match &simulation.value {
                    VerifiedSimulation::Succeeded(true) => {}
                    VerifiedSimulation::Succeeded(false) => {
                        anyhow::bail!("ERC-20 approve returned false for token {token}")
                    }
                    VerifiedSimulation::Denied => {
                        anyhow::bail!("ERC-20 approve simulation reverted for token {token}")
                    }
                }
                Ok(vec![
                    verification_decision(&allowance, Some(block), Some(block)),
                    verification_decision(&simulation, Some(block), Some(block)),
                ])
            }
        }
    }

    async fn verify_swap_anchors_before_sign(
        &self,
        anchors: &SwapQuoteAnchors,
    ) -> anyhow::Result<Vec<ExecutionVerificationDecision>> {
        let checkpoint = required_verification(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the token's implementation: paused, custom approve logic, or blacklist conditions
  2. Verify token state (owner balance, current allowance, pause status) before approving
  3. Use a standard, audited token or upgrade the token contract if you control it
  4. Try approving a smaller/standard amount (e.g. type(uint256).max) if the token imposes limits

Example fix

// before
let ok: bool = token.approve(spender, amount).call().await?;
// after
let paused = token.paused().call().await?;
anyhow::ensure!(!paused, "token paused; approve would return false");
let ok: bool = token.approve(spender, amount).call().await?;
anyhow::ensure!(ok, "approve returned false for token");
Defensive patterns

Strategy: validation

Validate before calling

let paused: bool = token.paused().call().await?;
anyhow::ensure!(!paused, "token paused; approve would return false");
let owner_balance: U256 = token.balance_of(owner).call().await?;
anyhow::ensure!(owner_balance > U256::zero(), "owner has no token balance");

Type guard

fn approve_will_apply(ret: &VerifiedSimulation) -> bool {
    matches!(ret, VerifiedSimulation::Succeeded(true))
}

Prevention

When it happens

Trigger: Pre-sign approval simulation of approve(spender, amount) returns VerifiedSimulation::Succeeded(false) — the call executes without reverting but the token contract returns false, indicating the approval did not apply.

Common situations: Non-standard ERC-20 tokens with balance/allowance conditions in approve; paused token contracts that return false instead of reverting; approving on a fork/simulation backend with stale token state; amount exceeding some token-specific cap.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/728c2bfd5c821256. Report an issue: GitHub.