Skip to main content

Troubleshooting

Use this page when API reads do not match what you expect. Most issues fall into one of four buckets: invalid request parameters, stale snapshots, using the wrong surface for the job, or expecting immediate read-after-write consistency.

400 Bad Request​

Both read endpoints and order preparation return 400 for requests that can't be accepted.

Common read cases:

  • /orders and /positions require a valid account address.
  • /markets/tickers validates addresses and symbols filters.
  • /markets/trading-capacity requires a valid symbol and a direction of long or short.
  • /rates validates period and averageBy.
  • /apy, /yield/gm-pools, and /performance/* validate their filters. /yield/gm-pools rejects malformed pool addresses.
  • /yield/gm-user-earnings requires a valid account address.
  • /trades since and until, and /trades/search fromTimestamp and toTimestamp, must be whole Unix seconds from 0 to 2147483647. A fractional or millisecond value returns Invalid since timestamp: whole seconds expected (with the field's name).
  • /stats/* rejects an unknown networks, versions, or metric value, and a from or to that isn't whole Unix seconds. Repeat a list parameter for each value (networks=arbitrum&networks=avalanche); a comma-separated list is rejected. A filter that matches no configured source, such as networks=megaeth&versions=v1, returns No configured source matches the requested networks and versions.

For schema validation failures, such as a missing required parameter or a value outside an enum, the message field is an object keyed by parameter name instead of a string.

POST /orders/txns/prepare can also return an application error:

  • INSUFFICIENT_LIQUIDITY means a Market Increase exceeds current JIT-aware trading capacity. Reduce the requested size or refresh capacity before preparing again. A resting increase can return the same code in validationWarnings instead because liquidity will be checked again when it triggers.
  • INSUFFICIENT_COLLATERAL means collateral remaining after fees would be below the on-chain minimum. Add collateral or change the order. For TWAP increases, every part must satisfy the minimum.

validationWarnings are non-blocking, but clients need to surface them before signing. If you receive a blocking 400, validate the query or change the order inputs before retrying; repeating the unchanged request won't succeed.

503 Service Unavailable​

A 503 from the GMX API means the request couldn't be served at that moment. Unlike a 400, the same request can succeed later, so retry with backoff.

  • /yield/gm-user-earnings returns 503 while earnings data is warming up on a deployment, or on a deployment where it isn't available.
  • /stats/* returns 503 on a deployment that doesn't serve protocol stats. The production hosts route /v1/stats to the Arbitrum deployment; if you still get a 503, call an Arbitrum host directly.
  • /pairs/solana returns 503 on a deployment that doesn't compute the GMX on Solana pair feed, and while its snapshot is still being built or is older than 15 minutes. Only the Arbitrum deployment computes it, and aggregators read it at https://solana.gmxapi.io/v1/pairs.
  • POST /orders/txns/prepare and other routes return 503 when the request runs past the 60 second server timeout.
  • A 503 whose body has code: "BACKEND_UNAVAILABLE" means the request reached a GMX API pool that doesn't serve that route. Retry, and if it persists, report it with the X-Trace-Id response header.

For the earnings, stats, and Solana pair feed cases, the response body is the generic {"message":"Internal Server Error"}, so use the route and the X-Trace-Id header, not the message, to tell the cases apart.

A value looks stale​

Start by checking whether you are reading from a cached or indexed surface.

  • Use Oracle API /markets/info when you need near-live market state.
  • Use Oracle API /markets when a 10 second cache window is acceptable.
  • Use GraphQL for historical activity, not for the latest write-path state.
  • Use a single composite read where possible instead of stitching unrelated polls together.

For GMX API market values, inspect each /v1/markets/values row's updatedAt field. It is a Unix timestamp in milliseconds and uses the older timestamp from the main market-values refresh and the virtualInventoryForPositionsInTokens refresh. A null value means at least one component has no successful refresh timestamp.

The default backend pulls market values every 5 seconds and marks a row stale for monitoring after 15 seconds. This threshold does not evict the row:

  • A total pull failure preserves the previous values and timestamps, which continue to age.
  • A market-specific failed refresh can preserve the previous values while setting updatedAt to null.
  • Disabled markets are excluded from backend values-staleness accounting.

Compare updatedAt with a freshness limit appropriate for your application. Don't treat an HTTP 200 response as proof that every value came from the latest pull.

For GMX API protocol stats (/stats/*), check the response metadata before trusting a total:

  • meta.completeness is partial when any source in scope isn't fresh. Stale sources still count toward the sums.
  • meta.sources[] reports each source's health (fresh, stale, or missing), lagSeconds, and lastError. A source becomes stale when its data lags by more than 900 seconds.
  • Timeseries points with provisional: true cover days that can still change.
  • tvl.poolsValuedAt and tvl.valuedAt report when TVL was valued.

For /yield/gm-user-earnings, window.endTimestamp reports when the earnings were calculated.

If you need one coherent account snapshot, prefer one positions call with includeRelatedOrders: true over multiple loosely coordinated reads.

A write succeeded, but the API still does not show it​

That is usually a surface mismatch or an operation that hasn't reached a final state.

  • SDK v2 and GMX API /orders/txns/* endpoints prepare, submit, and track signed order intents. Persist their requestId and poll order status on the same GMX API host that served prepare. The gmxapi.io and gmxapi.ai peers don't share order records, so status on the other peer returns 404 with the message Transaction not found. Don't fail over to the peer for that requestId; prepare the order again if the original host can't continue the chain. See Idempotency and race conditions.
  • The low-level GMX Relay surface accepts already-built relay-router calldata through POST /relay/submit. Persist the returned taskId and poll it through POST /relay/status.
  • SDK v1 and direct contracts submit transactions from your wallet or backend RPC client. Wait for the transaction receipt, then poll the read surface you care about.

Generic relay statuses are pending, executed, reverted, failed, and unknown. Treat unknown as inconclusive rather than failed: keep the operation pending until your own timeout, and don't resubmit the same signed calldata blindly. A 404 immediately after an accepted submission can also be transient while status becomes readable.

For a reverted relay operation, inspect reason and the top-level revertData when present. revertData contains public on-chain revert bytes and can be decoded by the client. If submission fails before returning a taskId, capture the X-Trace-Id response header; it may be the only support identifier.

Don't assume the first follow-up HTTP or GraphQL read will reflect final state. Relay processing, transaction inclusion, keeper execution, and indexing can complete at different times.

Positions and orders do not line up​

If your UI shows position state together with linked orders, fetch them from the same logical snapshot.

Recommended pattern:

import { GmxApiSdk } from "@gmx-io/sdk/v2";

const apiSdk = new GmxApiSdk({ chainId: 42161 });

const positions = await apiSdk.fetchPositionsInfo({
address: "0x9f7198eb1b9Ccc0Eb7A07eD228d8FbC12963ea33",
includeRelatedOrders: true,
});

Use a separate account-wide orders read only when you need a dedicated orders screen.

There is no documented public SLA​

The current manual docs do not publish a public SLA for these surfaces. Build your client as if network errors, timeouts, or stale snapshots can happen.

Recommended client behavior:

  1. Use endpoint-specific fallback URLs where they are documented.
  2. Add retries with backoff for safe read operations.
  3. Keep write confirmation logic separate from read polling logic.
  4. Log the exact surface you queried so you can distinguish GMX API, Oracle API, GraphQL, and SDK-backed reads during incident review.
  5. Capture the X-Trace-Id response header for GMX API failures. It is exposed to browser clients through CORS; include it with any requestId or taskId in support reports.

Next steps​