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:
- 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 aresign_l1_actionandsign_user_signed_action. The docs call confusing them the first common error. - 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.
- 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. - 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.
- 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
approveAgentis 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 error | What it means | What to do |
|---|---|---|
| Unfamiliar, changes between requests | The signature is wrong; the server recovers a different address every time | Work through the signing list; diff your bytes against the official SDK |
| Your agent address, stable | The 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” variant | The address has no deposit on this environment | Confirm mainnet vs testnet, and the account you actually funded |
| A stable address you recognise but did not expect | The wrong private key is loaded | Log 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.