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:
/ordersand/positionsrequire a valid account address./markets/tickersvalidatesaddressesandsymbolsfilters./markets/trading-capacityrequires a validsymboland adirectionoflongorshort./ratesvalidatesperiodandaverageBy./apy,/yield/gm-pools, and/performance/*validate their filters./yield/gm-poolsrejects malformed pool addresses./yield/gm-user-earningsrequires a validaccountaddress./tradessinceanduntil, and/trades/searchfromTimestampandtoTimestamp, must be whole Unix seconds from0to2147483647. A fractional or millisecond value returnsInvalid since timestamp: whole seconds expected(with the field's name)./stats/*rejects an unknownnetworks,versions, ormetricvalue, and afromortothat 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 asnetworks=megaeth&versions=v1, returnsNo 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_LIQUIDITYmeans 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 invalidationWarningsinstead because liquidity will be checked again when it triggers.INSUFFICIENT_COLLATERALmeans 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-earningsreturns503while earnings data is warming up on a deployment, or on a deployment where it isn't available./stats/*returns503on a deployment that doesn't serve protocol stats. The production hosts route/v1/statsto the Arbitrum deployment; if you still get a503, call an Arbitrum host directly./pairs/solanareturns503on 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 athttps://solana.gmxapi.io/v1/pairs.POST /orders/txns/prepareand other routes return503when the request runs past the60second server timeout.- A
503whose body hascode: "BACKEND_UNAVAILABLE"means the request reached a GMX API pool that doesn't serve that route. Retry, and if it persists, report it with theX-Trace-Idresponse 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/infowhen you need near-live market state. - Use Oracle API
/marketswhen a10second 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
updatedAttonull. - 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.completenessispartialwhen any source in scope isn'tfresh. Stale sources still count toward the sums.meta.sources[]reports each source'shealth(fresh,stale, ormissing),lagSeconds, andlastError. A source becomesstalewhen its data lags by more than900seconds.- Timeseries points with
provisional: truecover days that can still change. tvl.poolsValuedAtandtvl.valuedAtreport 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 theirrequestIdand poll order status on the same GMX API host that served prepare. Thegmxapi.ioandgmxapi.aipeers don't share order records, so status on the other peer returns404with the messageTransaction not found. Don't fail over to the peer for thatrequestId; 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 returnedtaskIdand poll it throughPOST /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:
- Use endpoint-specific fallback URLs where they are documented.
- Add retries with backoff for safe read operations.
- Keep write confirmation logic separate from read polling logic.
- Log the exact surface you queried so you can distinguish GMX API, Oracle API, GraphQL, and SDK-backed reads during incident review.
- Capture the
X-Trace-Idresponse header for GMX API failures. It is exposed to browser clients through CORS; include it with anyrequestIdortaskIdin support reports.
Next steps
- Use the Integration guide for workflow selection.
- Use Fallback URLs for Oracle API public read failover.