Skip to content

[BUG] SDK hangs indefinitely during simulation without timing out (missing AbortSignal in json-rpc fetch) #24354

Description

@XD637

What are you trying to do?

When deploying contracts to the Aztec testnet (e.g., Contract.deploy(...).send()) via the EmbeddedWallet and @aztec/aztec.js, the deployment often hangs indefinitely during the public simulation phase.

If the testnet RPC node (v5.testnet.rpc.aztec-labs.com) becomes congested, unresponsive, or silently drops the TCP connection during a heavy simulation query, the SDK freezes permanently. It never resolves, never throws an error, and completely bypasses the internal SDK retry mechanisms.

The console output gets stuck permanently at:
INFO: embedded-wallet:pxe:service Simulating transaction execution request to...

Code Reference

// The vulnerability is the use of native Node.js `fetch` without an AbortSignal timeout.

export async function defaultFetch(...) {
  let resp: Response;
  try {
    resp = await fetch(host, {
      method: 'POST',
      body: jsonStringify(body),
      headers: { 'content-type': 'application/json', ...extraHeaders },
      
      // BUG: Missing timeout. If the node drops the connection, this hangs forever.
      // Proposed Fix: Add `signal: AbortSignal.timeout(60000)` here
    });
  } catch (err) {
    // Because it never times out, it never throws, and the retry wrapper never catches it
    const errorMessage = `Error fetching from host ${host}: ${inspect(err)}`;
    throw new Error(errorMessage);
  }
}

Aztec Version

v5.0.0-rc.1

OS

Ubuntu 24.04

Browser (if relevant)

N/A

Node Version

v24.12.0

Additional Context

Because the native Node.js fetch lacks a default timeout, the defaultFetch Promise never rejects when the testnet RPC node gets stuck. Because it never throws an error, it completely bypasses the NoRetryError and makeBackoff logic built into the makeFetch wrapper.

Adding an AbortSignal.timeout(60000) to the fetch options will allow the request to cleanly reject with a TimeoutError, enabling your existing retry wrapper to catch it and handle testnet congestion gracefully rather than permanently freezing the developer's execution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-bugType: Bug. Something is broken.from-communityThis originated from the community :)

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions