Skip to main content

Errors & Rejection Reasons

Complete catalog of error codes and rejection reasons.

Error Response Format

HTTP Error Responses (Middleware)

Structured JSON errors from middleware (HTTP 4xx/5xx):

{
"error": "<code>",
"message": "<human message>"
}

Engine-Level Rejections (HTTP 200)

Trading rejections return HTTP 200 with OrderUpdateMessage.status = "REJECTED":

{
"timestamp": 1735000000000,
"info": { ... },
"status": "REJECTED",
"reason": "<exact rejection string>",
"filled_size": 0,
"order_id": null,
"wallet_address": "0x...",
"mmp_triggered": false
}

Critical: Do not rely on HTTP status codes for trading rejections. Always check status and reason fields.

Middleware Error Codes

These are returned as HTTP error responses with structured JSON body.

CodeHTTP StatusDescription
invalid_request400Cannot read request body
invalid_json400JSON parse failed
missing_field400Required field missing
invalid_wallet400Wallet string could not be parsed
invalid_parameter400Invalid parameter (e.g., size/price must be string)
signature_verification_failed400EIP-712 signature recovery failed
unsupported_endpoint400Middleware does not support this path
unauthorized401Signer is not authorized for wallet (agent auth failed)
internal_error500Agent authorization check failed unexpectedly

Engine Rejection Reasons

These appear in OrderUpdateMessage.reason when status="REJECTED".

Expired Instrument

Reason: "Instrument has expired"

Cause: Order placed on an instrument that has already expired.

Action: Check instrument expiry via GET /instruments or GET /markets.

Unfunded Account

Reason: "Account has no funds. Please deposit before trading."

Cause: Account cash balance is <= 0.0.

Notes:

  • New accounts may start with a default test balance (10_000_000 USDC)
  • Production deposit flow not yet implemented

Insufficient Margin

Reason: "Insufficient margin: worst case margin={:.2} (failing scenario: {ScenarioType})"

Example: "Insufficient margin: worst case margin=-12.34 (failing scenario: SpotChange)"

Cause: Pre-trade margin check found worst_loss + cash < 0 in at least one scenario.

Scenario types:

  • SpotChange: Spot price movement
  • VolChange: Volatility change
  • SkewChange: Skew change
  • KurtosisChange: Kurtosis change

Action:

  1. Check portfolio via GET /portfolio?wallet=...
  2. Review margin calculation in Margin
  3. Reduce position size or add collateral

Missing Spot Price

Reason: "Failed to get portfolio: No spot price available for underlying: {underlying}"

Cause: Engine cannot infer spot price for underlying needed to simulate fills.

Action: Check Hyperliquid spot price feed connectivity. Spot prices come from allMids WebSocket feed.

Tier Restrictions

Reason: "Tier1 users cannot go short. Filled long position: {filled}, total sell orders (including new): {total} (symbol: {symbol})"

Cause: Wallet is tier1 (long-only) and attempted to sell without sufficient filled long position.

Action:

  1. Check tier via GET /user-tier?wallet=...
  2. Upgrade to tier2 via POST /user-tier (requires admin or signature)
  3. Or ensure all sells are covered by filled long positions

Invalid Symbol

Reason: "Invalid symbol: {symbol}"

Cause: No orderbook exists for the symbol.

Action:

  1. Verify market exists via GET /instruments and GET /markets
  2. Check symbol format: UNDERLYING-YYYYMMDD-STRIKE-(C|P)

Symbol Parse Error

Reason: "Failed to parse symbol: {detail}"

Cause: Symbol does not match expected format.

Action: Verify symbol format matches UNDERLYING-EXPIRY-STRIKE-(C|P) or Deribit-style DDMMMYY.

Cancel Failures

Order Not Found

Reason: "Order not found for cancellation: {client_id}"

Cause: Order with given client_id not found.

Action: Verify client_id is correct and order exists via GET /orders?wallet=....

Orderbook Not Found

Reason: "Orderbook not found for symbol: {symbol}"

Cause: Orderbook does not exist for the symbol.

Action: Verify symbol is valid and market exists.

Order Not in Orderbook

Reason: "Order {id} not found in orderbook {symbol}"

Cause: Order ID exists but order is not in the orderbook (may be filled/canceled).

Action: Check order status via GET /orders?wallet=....

Order Already Filled

Reason: "Order {id} is already filled and cannot be cancelled"

Cause: Order was fully filled before cancel request.

Action: Check order status via GET /orders?wallet=....

Order Already Canceled

Reason: "Order {id} was already cancelled"

Cause: Order was already canceled.

Action: Check order status via GET /orders?wallet=....

Perp Order Validation

Reason: "Perp order missing underlying symbol"

Cause: Perp order does not include underlying field.

Action: Ensure perp order includes underlying symbol.

MMP Triggered

Reason: "MMP triggered during fill processing"

Cause: MMP limits breached during fill processing. Order was partially filled, then MMP triggered and canceled remaining quantity.

Action:

  1. Check MMP config via GET /mmp-config?wallet=...&currency=...
  2. Review fill window metrics
  3. Adjust MMP limits or reset MMP state via POST /mmp-config/reset

See MMP for full MMP semantics.

MMP Cancel (Other Orders)

Reason: "Order canceled by MMP trigger"

Cause: Order was canceled because another order for the same wallet+underlying triggered MMP.

Action: Review MMP configuration and fill activity.

Handler-Level Validation Errors

These return HTTP 400 before reaching the engine.

Price Validation

Error: "Price validation failed: Price {price} has {n} significant figures, maximum allowed is 5"

Cause: Price exceeds 5 significant figures.

Action: Round price to ≤ 5 significant figures.

Size/Price Format

Error: "Size must be greater than 0" or "Price must be greater than 0"

Cause: Size or price is <= 0 or cannot be parsed as float.

Action: Ensure size and price are valid positive numbers (as strings).

Invalid Symbol Format

Error: HTTP 400 with handler error message

Cause: Symbol does not parse as valid option symbol.

Action: Verify symbol format: UNDERLYING-YYYYMMDD-STRIKE-(C|P).

Bulk Order Errors

Bulk endpoints return per-item errors in BulkOrderResult.error:

  • "Signature verification failed: ..."
  • "Unauthorized: signer not authorized for wallet"
  • "Price validation failed: ..."
  • "Size must be greater than 0"
  • "Price must be greater than 0"
  • "Failed to send order to engine"
  • "No response from engine"

Each result includes index (position in request array) and success boolean.

WebSocket Errors

WebSocket control messages:

{
"type": "Error",
"message": "Authentication required for this channel"
}

Common errors:

  • "Authentication required for this channel": Attempted to subscribe to private channel without ?wallet=
  • "Client not found": Internal error (connection lost)

Error Handling Best Practices

  1. Always check status field: Do not rely on HTTP status codes for trading rejections
  2. Parse reason string: Use exact reason strings for programmatic handling
  3. Handle bulk errors: Check BulkOrderResult.error for each item in bulk requests
  4. Retry logic: Do not retry on REJECTED orders (fix the underlying issue first)
  5. Logging: Log full OrderUpdateMessage for debugging rejections

Error Code Reference Table

Rejection ReasonCategoryHTTP StatusAction
Instrument has expiredExpiry200Check expiry, use different instrument
Account has no funds...Funding200Deposit funds (when implemented)
Insufficient margin: ...Margin200Reduce size, add collateral, check portfolio
Failed to get portfolio: No spot price...Data200Check Hyperliquid feed connectivity
Tier1 users cannot go short...Tier200Upgrade to tier2 or cover sells
Invalid symbol: ...Symbol200Verify market exists
Order not found for cancellation: ...Cancel200Verify order exists
Order {id} is already filled...Cancel200Order already executed
Order {id} was already cancelledCancel200Order already canceled
MMP triggered during fill processingMMP200Review MMP config, adjust limits
Order canceled by MMP triggerMMP200Review MMP config, adjust limits
signature_verification_failedAuth400Check signature, string encoding
unauthorizedAuth401Approve agent or sign with wallet
Price validation failed: ...Validation400Round price to ≤ 5 sig figs

Debugging Rejections

  1. Check order details: Verify symbol, price, size, side are correct
  2. Check portfolio: GET /portfolio?wallet=... to see current positions and cash
  3. Check tier: GET /user-tier?wallet=... to verify tier restrictions
  4. Check MMP: GET /mmp-config?wallet=...&currency=... to review MMP limits
  5. Check market: GET /markets and GET /instruments to verify instrument exists
  6. Review logs: Server logs may contain additional context (not exposed via API)

References

  • Rejection logic: enforced in the trading engine
  • Margin checks: applied before order admission
  • Tier checks: enforced per wallet tier
  • Handler validation: standard request validation