Skip to content

Learn

Exchange APIs

Hyperliquid 'User or API Wallet does not exist': causes and fixes

Figures on this page are as of 2026-09. Fees, limits and margin tiers change — check the venue's own docs.

L1 error: User or API Wallet 0x0123... does not exist. means Hyperliquid recovered a signer address from your request and found neither an account nor an approved API wallet at that address. In the case Hyperliquid documents, the signature is wrong, so the address it recovers belongs to nobody.

This page is for developers signing Hyperliquid requests directly or through a library. By the end you will be able to tell, from the address inside the error, whether you have a signing bug or an agent-wallet problem — and what to change for each.

What this error actually means

Hyperliquid has no API key. Every /exchange request carries an EIP-712 signature, and the server works backwards from the signature and the payload to the address that must have produced it. That address is then resolved to a user, or to an API wallet (agent wallet) some user has approved. Nothing in the signed payload names the master account; attribution happens on the exchange side. The mechanics are in what is an agent wallet.

So the question the server is really answering is who signed this? If the bytes it reconstructs differ from the bytes you signed, the maths still produces an address — just not yours. Hyperliquid’s signing page describes it exactly: an incorrect signature “results in recovering a different signer based on the signature and payload”, and “the returned address also changes for different inputs.” It also warns that “an incorrect signature does not indicate why it is incorrect.”

Where you see it matters less than it seems. User reports on the official Python SDK’s issue tracker show it as a top-level {"status":"err","response":"L1 error: User or API Wallet 0x… does not exist."}; Hyperliquid’s own docs do not show that envelope. Either way, treat it as a rejection of the whole request, not of one order in a batch.

The usual cause: a signature that recovers someone else

The signing page lists the common errors. Each one makes the server reconstruct different bytes from the ones you signed:

  1. Using the wrong signing scheme. There are two: L1 actions (orders, cancels, leverage) and user-signed actions (approveAgent, withdrawals, transfers). In the official Python SDK they are sign_l1_action and sign_user_signed_action. The docs call confusing them the first common error.
  2. Field order in msgpack. L1 actions are hashed from a msgpack encoding of the action, and field order matters. A dict or object that serialises its keys in a different order signs a different action.
  3. Trailing zeroes on numbers. "0.10" and "0.1" are different bytes. The tick-and-lot-size page repeats the instruction: remove trailing zeroes when implementing signing.
  4. Upper-case characters in addresses. The docs recommend lowercasing any address before signing. A user report on the SDK repo (issue #103) shows an address with upper-case characters inside an action producing this error.
  5. Trusting local recover-signer. Recovering your own signature locally proves your code agrees with itself. It does not prove the server hashes the same bytes.

Two more follow directly from what goes into the signature. The environment is part of the signed message — source "a" or "b" for L1 actions, a hyperliquidChain field for user-signed ones — so a request signed for testnet and sent to mainnet recovers a different address. The optional vaultAddress for a sub-account or vault is also hashed, so signing with one and sending without it has the same effect.

The fix is to diff against the reference implementation. The docs defer to the official Python SDK for signature code. Build the same action with the SDK and your code, and compare the serialised bytes before comparing anything else.

Other causes, in order of likelihood

The agent wallet expired, was replaced, or was never approved. Hyperliquid’s docs do not say this produces this exact string. Third-party sources say it does: Tealstreet’s Hyperliquid connection docs attribute the error to the key having “most likely expired”, and Chainstack’s debugging guide lists an unapproved agent. It is consistent with Hyperliquid’s documented pruning rules, under which an API wallet stops being registered when:

  • it expires;
  • it is deregistered — an existing unnamed wallet is deregistered when a new unnamed one is approved, and a named one when approveAgent is sent again with the same name;
  • the account that registered it no longer has funds (Chainstack’s guide separately lists a master with zero balance).

The second rule has a nasty consequence: a second bot or tool that “sets up its own API wallet” without a name silently evicts the first. If a working setup broke the day someone connected something else, look there.

The wrong key is loaded. An environment variable, a config file from another project, or a key for the other environment. The address in the error will be stable and will be the address of whatever key you actually loaded.

The adjacent string: “Must deposit before performing actions”

The signing page lists a sibling error in the same breath:

Must deposit before performing actions. User: 0x123...

Check it the same way. If the User address is unfamiliar and changes between requests, it is the signing problem above. If it is your own master address and stays put, the plain reading of the message applies: that address has no deposit on the environment you are calling. On testnet, note that the faucet requires a mainnet deposit from the same address, and email (Privy) logins get a different address on mainnet and testnet — per the testnet faucet page.

How to confirm which one you have

Everything turns on the address in the error. Send the request twice, each with a fresh nonce, and compare the addresses:

Address in the errorWhat it meansWhat to do
Unfamiliar, changes between requestsThe signature is wrong; the server recovers a different address every timeWork through the signing list; diff your bytes against the official SDK
Your agent address, stableThe signature is fine; the exchange does not recognise that agent (third-party sources: expired or unapproved)Approve a new agent address — do not re-approve an old one, since pruned nonce state can allow replays. Check nothing else replaced it
Your master address, stable, in the “Must deposit” variantThe address has no deposit on this environmentConfirm mainnet vs testnet, and the account you actually funded
A stable address you recognise but did not expectThe wrong private key is loadedLog the signer address at startup

The cheapest prevention is that last line: derive and log the signer address when your process starts, next to the master address it will query. If you are building error handling for more than one venue, the general shape is in API error handling patterns.

FAQ

Why does the address in the Hyperliquid error change on every request?

Because the signature does not match the payload the server reconstructs, and recovering a signer from a mismatched pair produces a different address for different inputs. Hyperliquid’s signing page documents this behaviour. It points to a serialisation or signing bug — scheme, field order, trailing zeroes or upper-case addresses — not to a problem with your account.

Does “User or API Wallet does not exist” mean my agent wallet expired?

It can, but Hyperliquid’s docs do not say so; the documented cause is an incorrect signature. Third-party sources, including Tealstreet and Chainstack, attribute the error to expired or unapproved agents as well. If the address in the error is your agent’s address and it is stable, an expired or replaced agent is the likely explanation.

Why did my Hyperliquid bot break after I connected another tool?

Approving a new unnamed API wallet deregisters the existing unnamed one. If the new tool created its own unnamed agent, your bot’s agent stopped being registered. Give each tool its own named agent, and approve a fresh address for the broken one rather than re-approving the old one.

What does “Must deposit before performing actions” mean on Hyperliquid?

The signing page lists it beside the “does not exist” error. If the User address in it changes between requests, treat it as a signing bug. If it is your own address and stable, that address has no deposit on the environment you are calling — often a mainnet/testnet mix-up, or a login that has different addresses on each.