Troubleshooting
Error identifiers you may encounter, what they mean, and what to do about them.
Charts stay blank or report WebGL problems
Charts are drawn with WebGL. If the browser cannot create a WebGL context at all, the chart reports that it failed to initialize and asks you to update your browser or enable hardware acceleration — those two steps are the remedy. If the graphics context is lost later, for example after a GPU reset, a discarded tab, or resuming a mobile device, the chart says rendering is paused and will resume when the GPU recovers. Recovery is automatic: when the browser restores the context the chart rebuilds its GPU resources and re-uploads the current candles, so no page reload is needed. If the rebuild itself fails, the chart stays paused and the failure is written to the browser console.
What your browser has to provide
The candlestick and heatmap charts are drawn on a WebGL2 context. The renderer asks the canvas for webgl2 specifically and raises an error when the browser returns nothing, which is the point where the chart reports that WebGL failed to initialize and suggests updating the browser or enabling hardware acceleration. There is no software drawing path for the candles themselves — the annotation layer uses a plain 2D canvas, but without WebGL2 the price series does not render at all. A browser that supports only the first WebGL generation, or one running with acceleration disabled, therefore produces a blank chart with that exact message.
When a context is created and later lost — a GPU driver reset, a discarded background tab, a mobile device resuming — the chart cancels the browser's default handling of the loss, which is what makes automatic restoration possible in the first place, and switches to the paused state. On restoration it rebuilds its GPU resources, invalidates its buffer version so every candle is uploaded again, and returns to drawing. Each step leaves a line in the browser console prefixed [WebGLChart]: one for the loss, one for the successful rebuild, and an error line if the rebuild fails. Those three lines are the quickest evidence to include in a report about a blank chart.
Sign-in redirects, upgrade prompts and disabled features
Opening a protected page while signed out sends you to the sign-in page with your destination preserved, and returns you there afterwards; the same situation on an API request answers 401 with UNAUTHORIZED. If you are signed in but your plan does not cover the page, you are redirected to the upgrade page with the required tier in the query string, and the equivalent API request answers 402 with PAYMENT_REQUIRED plus the feature key. Live chat is gated the same way — on the preview tier the support page shows an upgrade call to action instead of chat. A feature switched off by an operator answers 503 with KILL_SWITCH and a Retry-After header.
Locked, clamped and delayed — what is not a fault
Two visual signals mean "your plan does not include this", and neither is an error. A gated surface is covered by a padlock overlay that intercepts both mouse clicks and keyboard activation and opens the upgrade dialog instead of the underlying link. A partially visible data widget gets an inline gold pill instead — used where data is present but reduced, such as a delayed tick or a clamped history depth. If a chart shows fewer bars than you expect and carries that pill, the history was shortened on purpose rather than lost.
Timing explains a third observation. A gate stays deliberately indeterminate until your entitlements have loaded: before that it is hidden and inert, so paying users never see a locked state flash before it unlocks. The visible consequence is that a gated tile can be empty for a moment right after a page load. On the server, the same policy answers API requests with 402 and a payload naming the feature key and the required tier, while a browser navigation is redirected to the upgrade page with the source, the original path and the required tier in the query string — which is why the upgrade page can tell you exactly what you tried to open.
The error codes an API response carries
Every response from the app's own API has a fixed shape. A success carries success: true, a data payload and a timestamp. A failure carries success: false and an error object holding a machine-readable code, a human-readable message, and optionally a target naming the field at fault, a details object with extra context, and a doc_url. Quote the code when you report a problem: the code is stable, the message wording is not. Twelve codes exist, and each one is tied to a single HTTP status.
Two response shapes sit outside that set. Older endpoints answer in a legacy envelope of code, msg, data and success, where code is a numeric string grouped by class: 10xxx for input problems, 20xxx for authentication, 30xxx for authorization, 40xxx for missing or conflicting resources, 50xxx for server faults and 60xxx for upstream services. Database problems are translated before they reach you: a lost connection becomes 503 with "Database temporarily unavailable", a query that exceeds its time limit becomes 504 with "Request timed out", a duplicate becomes 409, and a constraint violation becomes 400. The first two are worth retrying; the last two will repeat until the input changes.
- BAD_REQUEST — 400. The request was malformed. Check the parameters you sent.
- VALIDATION_ERROR — 400. One input failed validation; the response names it in target.
- UNAUTHORIZED — 401. No valid session. Sign in and repeat the request.
- PAYMENT_REQUIRED — 402. Signed in, but the plan does not cover it. details carries featureKey, requiredTier and, for domain gates, requiredDomain.
- FORBIDDEN — 403. Authenticated but not permitted. The precise reason is deliberately kept server-side.
- NOT_FOUND — 404. No such resource at that address.
- CONFLICT — 409. The resource changed underneath you, or already exists. Reload and retry.
- PAYLOAD_TOO_LARGE — 413. The request body exceeds the accepted size.
- RATE_LIMITED — 429. Too many requests. The response carries Retry-After, X-RateLimit-Limit and X-RateLimit-Remaining; AI endpoints have their own separate budget and answer with the distinct code AI_RATE_LIMITED.
- INTERNAL_ERROR — 500. An unexpected server fault. Report it with your Error ID.
- UPSTREAM_ERROR — 502. A service the endpoint depends on failed. Retry later.
- SERVICE_UNAVAILABLE — 503. Temporarily unavailable. Note that a feature switched off on purpose uses a different 503 body, described below.
Kill switches: who turns a feature off, and for how long
A kill switch is an off switch for one named feature, operated by the Athenum team rather than by you, and it is the reason a page can be unreachable while the rest of the app is healthy. Two different situations produce the same 503. If the feature is switched off because its backend has not shipped yet, the error page reads "Coming Soon" and explains that the feature is in development. If an operator turned a working feature off, the page reads "Temporarily Unavailable". Both responses identify themselves with the code KILL_SWITCH and a stable public feature name such as funding-heatmap or cme-detector.
The response tells you how long to wait. Each switch carries its own Retry-After value: 60 seconds for the funding heatmap, 1800 seconds for the CME detector, and 300 seconds for anything without an explicit setting. API callers get the same information as application/problem+json, including a defaultKilled flag that distinguishes the unbuilt case from the operator case. The 503 itself is never cached, and successful responses on switchable endpoints are capped at ten seconds of caching, so a switch flip reaches you quickly; a shared cache may still serve the previous answer for roughly fifteen seconds after a flip.
A killed route is normally not reachable by clicking. Routes that a switch blocks entirely are filtered out of the home page cards and hidden from the command palette, so the 503 is mostly seen by people using a bookmark, a direct link or the API. Not every switch blocks a route: some change behavior in place instead, which is why a feature can be affected without any page returning 503. Kill-switch pages carry no Error ID, because the response is a deliberate decision rather than an incident, and no identifier is invented to fill the field.
Site-wide maintenance versus a single failing feature
A planned maintenance window looks different from every other failure. Instead of the usual error page you get a standalone document headed "We'll be back soon", with no navigation, no Error ID and no support link. It is served with HTTP 503 and a Retry-After of one hour. The page is fully self-contained — its styling and logo are embedded, and it makes no network calls — so it still renders when the backend, the database and analytics are all unreachable. It is also marked as non-indexable, so search engines treat the outage as temporary.
The gate is deliberately narrow. It only replaces browser page requests: GET or HEAD requests that ask for HTML. API calls under /api/ pass straight through, as do the container health endpoints and any request for scripts, styles or fonts. A consequence worth knowing: during maintenance an API client or an embedded integration can keep working normally while the browser shows the maintenance page. If you see "We'll be back soon" the whole site is affected; if you see a 503 error page naming one feature, only that feature is.
Reading an empty panel: the badge names the failure
Panels on the macro pages carry a small badge in the corner, and that badge is the fastest way to tell an outage from a quiet data source. Five of the badge states describe real data, and two describe the panel itself. Because the badge is derived from the same freshness rules the panel uses to draw, it cannot claim a state the data does not support: a panel with nothing to show is never labelled STALE, and a missing value is never replaced by a stand-in number.
Panel-level shells add a second layer of information. A first load in flight renders a skeleton with no verdict and no copy. A read that failed in transport renders an error card with the wording "Fleet read failed — the source may still be live. Retry to reload." and a retry button — the source may well be healthy, and retrying is the correct response. A read that succeeded but returned no rows renders "Awaiting Fleet-Bridge" with the UNAVAILABLE badge. Those two look similar and mean opposite things: the first is a connection problem you can retry, the second means the series has not started flowing yet.
TradeFI panels report the reason in words instead of a badge. When the data provider failed, the panel says the data is temporarily unavailable. When the provider answered with nothing, it says no data is available for that symbol. Institutional ownership adds a third case: a note explaining that the view is an official tracked-institution subset and representative rather than exhaustive — that is a scope statement, not a fault. Peer lists behave the same way and name a non-default source in a note above the panel when one was used.
- LIVE — an intraday or realtime observation inside its expected cadence.
- EOD — an honest period close for a daily, weekly, monthly or quarterly series.
- STALE — a real value, but older than the series' expected update cadence.
- FALLBACK — last-known-good cached data, explicitly not the current value.
- MODEL — a computed heuristic or Athenum construction, not a direct observation.
- UNAVAILABLE — the panel is in an error state and nothing is rendered.
- LOADING — the first load is still in flight and freshness is not yet determined.
Reporting a problem: your Error ID
When a request fails, the error page shows the HTTP status, a short title and — when one was generated — an Error ID. That identifier is minted for your specific incident and attached to the recorded error report, so support can find exactly your case. Use the Copy button next to it, then choose “Chat with support”: the link carries the Error ID through to the support page. When reporting, include the Error ID, the page address and what you were doing. Not every error has one — for a temporarily disabled feature no placeholder is invented, so the field is simply absent.
Where your Error ID goes after you copy it
The identifier on the error page is minted on the server, once per incident, at the moment the failure is caught. The server writes a log entry containing that identifier together with the HTTP status, the error name, the request path, the request method and a timestamp; in production the entry deliberately omits stack traces and internal detail. The same identifier is attached to the incident sent to error tracking, so support can correlate your copy of the id with the recorded failure. Requests that simply hit a missing page are the exception: they still receive an identifier, but they are not forwarded to error tracking.
What the browser receives back is intentionally thin — a generic message plus the identifier — so no internal detail leaks through the page. Pressing "Chat with support" carries the identifier onward: the link opens the support page with an incident topic, the Error ID and a request to open chat, rather than launching a chat widget on the failing page. If the Copy button appears to do nothing, the clipboard write was refused — this happens on insecure origins or when clipboard permission is denied — and the failure is logged in the browser console; select the identifier by hand in that case.
Whether live chat is actually available on the support page depends on three checks made before the page renders. Chat requires a paid plan: on the preview tier the page shows an upgrade prompt in its place. Chat is also withheld while the support messenger switch is off, and while the request needs consent that has not been recorded — which is the case for requests that look European, British or Swiss, and for requests that carry no country signal at all, since the check fails closed. In every one of those cases the page still offers email and the Discord community, and those two are always present regardless of plan.
What to check before you report a problem
Most of what support would ask you is visible on the screen already. The checks below take under a minute and turn "it's broken" into a report that can be acted on. Work from the outside in — whole site, then page, then panel — because each layer has a different owner and a different fix. Nothing here requires developer tools except the two items that explicitly mention them.
- Establish the scope. Is every page affected, one page, or one panel inside an otherwise working page? "We'll be back soon" means the whole site; a 503 page naming a feature means only that feature.
- Read the wording verbatim. "Coming Soon" and "Temporarily Unavailable" are different situations even though both are 503, and the panel texts "Fleet read failed" and "Awaiting Fleet-Bridge" mean opposite things.
- Look for a badge. LOADING, STALE, FALLBACK and UNAVAILABLE each describe a different condition, and a padlock or gold pill means a plan limit rather than a fault.
- Retry once after waiting. Temporary responses state their own retry window in the Retry-After header, visible in the browser's network panel; retrying earlier will usually return the same answer.
- For a blank chart, open the browser console and look for lines prefixed [WebGLChart], then confirm the browser is current and hardware acceleration is enabled.
- Copy the Error ID if one is shown. If the Copy button does nothing, select it manually — the clipboard write can be refused by the browser.
- Note the page address, the time, and what you did immediately before the failure. The Error ID identifies the incident; those three identify what you were trying to achieve.
Collector error codes
The futures data collector tags every failure with a stable code, and that code appears in square brackets wherever the error text is shown or logged. These are backend identifiers: seeing one in a support reply or a status note tells you which stage failed, and whether the collector retried, fell back to another source, or gave up.
| Code | Meaning | Recovery |
|---|---|---|
FUT-1001HttpFailed | The request to the exchange never completed.HTTP request failed for {exchange}: {message} | Retried |
FUT-1002ExchangeError | The exchange answered, but with an error of its own.Exchange error for {exchange}: {message} | Falls back to another source |
FUT-1003RateLimitExceeded | The exchange rejected the call for exceeding its rate limit.API rate limit hit for {exchange} | Retried |
FUT-1004ParseFailed | A response arrived but could not be read in the expected shape.Parse error for {exchange}: {message} | Falls back to another source |
FUT-1005DatabaseError | Writing or reading the collected data failed.Database error: {source} | Retried |
FUT-1006SerializationError | A payload could not be encoded or decoded, so retrying will not help.Serialization error: {source} | Fatal |
FUT-1007RequestError | The HTTP client itself failed before or during the call.Request error: {source} | Retried |
FUT-1008ConfigError | Configuration or environment is wrong — this is not a market-data problem.Config error: {message} | Fatal |
FUT-1009RateLimiterInternal | The collector's own rate limiter failed.Rate limiter error: {message} | Retried |
FUT-1010Unknown | A failure that does not match any of the categories above. No fixed recovery action is defined for it.{message} | Unclassified |
Volume-delta error codes
The volume-delta endpoint returns a VDLT_-prefixed code and a hint. Retryable errors are transient — the same request can succeed shortly afterwards; the others need the request itself to change.
| Code | Retryable | Hint returned by the API |
|---|---|---|
VDLT_EXCHANGE_TIMEOUT | Yes | Retry after a few seconds. The exchange may be experiencing high load. |
VDLT_EXCHANGE_RATE_LIMITED | Yes | Retry after 30s. Reduce request frequency. |
VDLT_EXCHANGE_BAD_RESPONSE | No | The exchange returned malformed data. Try a different exchange filter. |
VDLT_EXCHANGE_UNAVAILABLE | Yes | The exchange API is down. Data from other exchanges is still available. |
VDLT_OHLC_SOURCE_FAILED | Yes | Binance is the primary price source. Retry in a few seconds. |
VDLT_NO_DATA | No | All configured exchanges failed. Check the exchanges parameter or try again later. |
VDLT_INVALID_INTERVAL | No | Valid intervals: 1m, 3m, 5m, 15m, 30m, 1h, 4h, 8h, 12h, 1d |
VDLT_INVALID_ASSET | No | Valid assets: BTC, ETH, SOL |
VDLT_PARAM_TOO_LONG | No | Reduce the number of exchange IDs. Maximum 2000 characters. |
The hint column reproduces the English string the API returns; it is not localized.
Still stuck
Contact support from inside the app. There is no published service-level target, uptime figure or guaranteed response time, so this page does not state one.