Overview
Signature errors on Hyperliquid often produce cryptic messages that don’t point to the actual cause. This guide covers the most common issues developers encounter, based on real problems reported in the Hyperliquid developer community.For foundational signing concepts, see the authentication guide and signing overview.
”User or API Wallet does not exist” with changing addresses
This error is one of the most confusing because the wallet address in the error message changes with every request:Why the address changes
The address isn’t random—it’s the recovered address from your signature. Hyperliquid uses ECDSA signature recovery to determine who signed the message. When your signature is malformed, the recovery produces a different (invalid) address each time.Root causes
Key ordering in action objects
Key ordering in action objects
The action hash depends on msgpack serialization, which is order-sensitive. Different key orders produce different hashes, leading to different recovered addresses.
Address case sensitivity
Address case sensitivity
Hyperliquid requires lowercase addresses for signature verification:
Agent wallet not approved
Agent wallet not approved
If you’re using an agent wallet that hasn’t been approved by the master account, signature recovery fails:If your agent isn’t listed, approve it first:
Account has no funds
Account has no funds
Even with a valid signature, the error appears if the master account has zero balance:Deposit USDC before attempting trades.
Debugging checklist
1
Log the exact action object
Print the action just before signing to verify structure and key order
2
Verify address formatting
Ensure all addresses are lowercase with
0x prefix3
Check agent approval
Query
user_state to confirm agent is in agentAddresses list4
Verify account balance
Confirm the master account has collateral deposited
5
Compare with SDK output
Run the equivalent SDK method and compare the generated signature
chainId mismatch in browser wallets
When integrating with viem or wagmi, you may encounter:Why this happens
Hyperliquid L1 actions require signing with chainId 1337, but your wallet is connected to Arbitrum (42161), Optimism (10), or another chain. Browser wallets enforce that the signing chain matches the connected chain.Solutions
- Use agent wallets (recommended)
- Custom chain definition
- Sign with local account
Create an agent wallet for trading operations. The agent signs server-side with chainId 1337, avoiding the browser mismatch entirely:
Best practice for frontends
For production applications, use this two-wallet pattern:- Browser wallet (user’s MetaMask/WalletConnect) — signs
approveAgent(chainId 0x66eee matches Arbitrum) - Agent wallet (generated keypair stored locally) — signs all L1 actions (chainId 1337)
TypeScript SDK options
Hyperliquid has two community TypeScript SDKs:| SDK | Maintainer | Features |
|---|---|---|
| @nktkas/hyperliquid | nktkas | Full API coverage, PrivateKeySigner, viem/ethers support |
| nomeida/hyperliquid | nomeida | Simpler API, good for quick integrations |
@nktkas/hyperliquid examples
Install:reserveRequestWeight for HIP-3 builders
If you’re building a HIP-3 DEX and need to push oracle prices, you’ll encounterreserveRequestWeight—an action that uses a unique hybrid signing pattern.
The edge case
Most actions follow clear rules:- L1 actions → phantom agent schema, signed by agent wallet
- User-signed actions → direct EIP-712, signed by user wallet
reserveRequestWeight breaks this pattern: it uses the agent-style schema but must be signed by the user wallet.
This hybrid exists because oracle updates need the authority of the main account but use the same submission path as L1 actions.
Implementation
Error reference
| Error message | Likely cause | Solution |
|---|---|---|
| ”User or API Wallet does not exist” | Signature recovery failed | Check key ordering, address case, agent approval |
| ”Invalid signature” | Wrong signing scheme | L1 actions: chainId 1337; user-signed: chainId 0x66eee |
| ”Provided chainId must match” | Browser wallet chain mismatch | Use agent wallet for L1 actions |
| ”Invalid or expired nonce” | Nonce not in milliseconds | Use get_timestamp_ms() or Date.now() |
| ”Failed to deserialize” | Missing required fields | Ensure all required fields present (e.g., grouping for orders) |
| “Agent not approved” | Agent wallet not authorized | Call approve_agent() first |
| ”Agent already exists” | Duplicate agent name | Use unique names per agent |
Summary
Most Hyperliquid signature errors fall into three categories:- Serialization issues — Key ordering, address casing, missing fields
- Chain ID confusion — Using wrong chainId for L1 vs user-signed actions
- Wallet configuration — Agent not approved, no funds, wrong wallet type
Related resources
- Authentication guide — Overview of both signing mechanisms
- L1 action signing — Phantom agent construction details
- User-signed actions — Agent approval and transfers
- Hyperliquid API reference — Complete endpoint documentation