Price (USD) chart timeframe selector freezes after repeated switches, requires page refresh to restore #148

Closed
opened 2026-05-07 13:08:48 +00:00 by totdking · 21 comments
totdking commented 2026-05-07 13:08:48 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-05-07 13:13:16 +00:00 (Migrated from gitlab.com)

Issue Summary

After selecting a pair on the /trade page, the Price (USD) chart timeframe selector stops responding after approximately 5–6 consecutive timeframe changes. Once frozen, clicking any timeframe button produces no visual update and no chart rebind. The selector shows no loading state, no error, and no indication that it is stuck. A full page refresh is required to restore normal function.


Reproduction Steps

  1. Complete full local setup (LocalTerra running, contracts deployed, indexer running, frontend running)
  2. Navigate to /trade
  3. Select any pair from the pair selector
  4. On the Price (USD) chart, click through the timeframe options (e.g. 1m → 5m → 15m → 1h → 4h → 1d) repeatedly
  5. After approximately 5–6 changes, click any timeframe button
  6. Observe: the chart does not update, the selector appears to accept the click but the chart remains frozen on the last applied timeframe
  7. Refresh the page, timeframe switching resumes normally

Expected Behavior

Each timeframe selection should update the Price (USD) chart to the corresponding interval without limit on the number of consecutive switches. No refresh should be required to continue switching timeframes.


Actual Behavior

After approximately 5–6 timeframe changes, the selector freezes. Subsequent clicks on any timeframe button are visually acknowledged but produce no chart update. The chart remains stuck on the last applied timeframe. No error state, spinner, or user-facing message is shown. Only a full page refresh restores the control.


Environment Details

Field Value
OS macOS (Apple M1 Pro, 14-inch)
Browser Google Chrome (desktop)
Viewport 1470×864
Network localterra (local Docker)
Frontend VITE_NETWORK=local npm run dev
Indexer Running (make indexer-dev)
Contracts Deployed via make deploy-local

Wallet / Device Details

  • Wallet: Station browser extension
  • Network configured in Station: localterra — LCD http://localhost:1317, RPC http://localhost:26657

Screenrecord

See attached clip showing the frozen timeframe selector with the chart stuck on the last applied interval after repeated switches.


Severity / Impact

P2 Polish. Chart remains visible but is no longer interactive the timeframe selector is silently dead until refresh. This impairs pre-trade context reading for any trader doing analysis on the current pair. No funds are at risk and order placement is unaffected. The freeze pattern (silent after N interactions, no error surfaced) suggests an unhandled promise rejection, a stale event listener, or a chart library subscription that is not being torn down and re-initialised on repeated pair or timeframe changes.

It is classified under **W6-C1 in [116](**https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/116#:~:text=Work%20items-,%23116,-Full%20deep%20visual) (Chart embed / timeframe controls — Updates dimension: "pair switch rebinds chart; no stale symbol on axis"). Discovered during W4-C2 inspection on /trade.

cc : @PlasticDigits

### Issue Summary After selecting a pair on the `/trade` page, the Price (USD) chart timeframe selector stops responding after approximately 5–6 consecutive timeframe changes. Once frozen, clicking any timeframe button produces no visual update and no chart rebind. The selector shows no loading state, no error, and no indication that it is stuck. A full page refresh is required to restore normal function. --- ### Reproduction Steps 1. Complete full local setup (LocalTerra running, contracts deployed, indexer running, frontend running) 2. Navigate to `/trade` 3. Select any pair from the pair selector 4. On the Price (USD) chart, click through the timeframe options (e.g. 1m → 5m → 15m → 1h → 4h → 1d) repeatedly 5. After approximately 5–6 changes, click any timeframe button 6. Observe: the chart does not update, the selector appears to accept the click but the chart remains frozen on the last applied timeframe 7. Refresh the page, timeframe switching resumes normally --- ### Expected Behavior Each timeframe selection should update the Price (USD) chart to the corresponding interval without limit on the number of consecutive switches. No refresh should be required to continue switching timeframes. --- ### Actual Behavior After approximately 5–6 timeframe changes, the selector freezes. Subsequent clicks on any timeframe button are visually acknowledged but produce no chart update. The chart remains stuck on the last applied timeframe. No error state, spinner, or user-facing message is shown. Only a full page refresh restores the control. --- ### Environment Details | Field | Value | |-------|-------| | OS | macOS (Apple M1 Pro, 14-inch) | | Browser | Google Chrome (desktop) | | Viewport | 1470×864 | | Network | `localterra` (local Docker) | | Frontend | `VITE_NETWORK=local npm run dev` | | Indexer | Running (`make indexer-dev`) | | Contracts | Deployed via `make deploy-local` | --- ### Wallet / Device Details - **Wallet:** Station browser extension - **Network configured in Station:** localterra — LCD `http://localhost:1317`, RPC `http://localhost:26657` --- ### Screenrecord > See attached clip showing the frozen timeframe selector with the chart stuck on the last applied interval after repeated switches. --- ### Severity / Impact **P2 Polish.** Chart remains visible but is no longer interactive the timeframe selector is silently dead until refresh. This impairs pre-trade context reading for any trader doing analysis on the current pair. No funds are at risk and order placement is unaffected. The freeze pattern (silent after N interactions, no error surfaced) suggests an unhandled promise rejection, a stale event listener, or a chart library subscription that is not being torn down and re-initialised on repeated pair or timeframe changes. It is classified under **W6-C1 in \[116\](**https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/116#:\~:text=Work%20items-,%23116,-Full%20deep%20visual) (Chart embed / timeframe controls — Updates dimension: "pair switch rebinds chart; no stale symbol on axis"). Discovered during W4-C2 inspection on `/trade`. cc : @PlasticDigits
totdking commented 2026-05-07 17:32:42 +00:00 (Migrated from gitlab.com)

mentioned in issue #116

mentioned in issue #116
PlasticDigits commented 2026-05-09 05:07:30 +00:00 (Migrated from gitlab.com)

@totdking Video clip is missing - seems it did not properly attach

@totdking Video clip is missing - seems it did not properly attach
totdking commented 2026-05-11 12:29:00 +00:00 (Migrated from gitlab.com)

mentioned in issue #151

mentioned in issue #151
PlasticDigits commented 2026-05-25 02:10:43 +00:00 (Migrated from gitlab.com)

mentioned in commit d04b0e98ff

mentioned in commit d04b0e98ff98713f4096ca06125bca7bf1683376
PlasticDigits commented 2026-05-25 02:11:50 +00:00 (Migrated from gitlab.com)

Fix landed on main (d04b0e9)

Root cause: Each timeframe change set React Query isLoading, which unmounted PriceChartLightweightCanvas and re-ran async createChart. After ~5–6 rapid switches, overlapping inits left the chart stuck while interval buttons still updated.

Changes:

  • PriceChart: placeholderData: keepPreviousData so the plot stays mounted during interval refetch; first load only shows full-panel loading; refetch shows data-testid="price-chart-interval-loading" overlay.
  • PriceChartLightweightCanvas: chartInitIdRef drops stale async inits and tears down orphan chart instances.
  • Vitest regression: reuses one chart instance across many interval switches (PriceChart.test.tsx).
  • Docs: trade page price chart invariants + skills/AGENTS_FRONTEND_PRICE_CHART.md invariant #10.

Verification checklist (please confirm on /trade with LocalTerra + indexer)

  • Select a pair; open Price (USD) chart.
  • Click through 1m → 5m → 15m → 1h → 4h → 1d → 1w at least twice without refreshing.
  • After each click, candles/axis update to the new interval (may briefly show “Updating interval…” overlay).
  • No silent freeze after 6+ switches; no page refresh required.
  • Toggle MA/RSI after interval stress — overlays still work.
  • Switch pair — chart still loads and intervals remain responsive.

@brouie — please verify on your environment when you have a moment. Leaving the issue open until QA signs off.

/cc @totdking

## Fix landed on `main` (d04b0e9) **Root cause:** Each timeframe change set React Query `isLoading`, which **unmounted** `PriceChartLightweightCanvas` and re-ran async `createChart`. After ~5–6 rapid switches, overlapping inits left the chart stuck while interval buttons still updated. **Changes:** - `PriceChart`: `placeholderData: keepPreviousData` so the plot stays mounted during interval refetch; first load only shows full-panel loading; refetch shows `data-testid="price-chart-interval-loading"` overlay. - `PriceChartLightweightCanvas`: `chartInitIdRef` drops stale async inits and tears down orphan chart instances. - Vitest regression: *reuses one chart instance across many interval switches* (`PriceChart.test.tsx`). - Docs: [trade page price chart invariants](docs/frontend.md#trade-page-price-chart-invariants) + [`skills/AGENTS_FRONTEND_PRICE_CHART.md`](skills/AGENTS_FRONTEND_PRICE_CHART.md) invariant **#10**. ## Verification checklist (please confirm on `/trade` with LocalTerra + indexer) - [ ] Select a pair; open Price (USD) chart. - [ ] Click through **1m → 5m → 15m → 1h → 4h → 1d → 1w** at least **twice** without refreshing. - [ ] After each click, candles/axis update to the new interval (may briefly show “Updating interval…” overlay). - [ ] No silent freeze after 6+ switches; no page refresh required. - [ ] Toggle MA/RSI after interval stress — overlays still work. - [ ] Switch pair — chart still loads and intervals remain responsive. @brouie — please verify on your environment when you have a moment. Leaving the issue **open** until QA signs off. /cc @totdking
totdking commented 2026-05-26 14:09:17 +00:00 (Migrated from gitlab.com)

Verification checklist (please confirm on /trade with LocalTerra + indexer)

  • Select a pair; open Price (USD) chart.
  • Click through 1m → 5m → 15m → 1h → 4h → 1d → 1w at least twice without refreshing.
  • After each click, candles/axis update to the new interval (may briefly show “Updating interval…” overlay).
  • No silent freeze after 6+ switches; no page refresh required.
  • Toggle MA/RSI after interval stress — overlays still work.
  • Switch pair — chart still loads and intervals remain responsive.

Issue noticed

The change of pairs on /trade always brings out an error from the page

Screen record:

This happens for all pairs across the /trade tab

Screen Recording 2026-05-26 at 14.53.00.mov

cc: @PlasticDigits

## Verification checklist (please confirm on `/trade` with LocalTerra + indexer) * [x] Select a pair; open Price (USD) chart. * [x] Click through **1m → 5m → 15m → 1h → 4h → 1d → 1w** at least **twice** without refreshing. * [x] After each click, candles/axis update to the new interval (may briefly show “Updating interval…” overlay). * [x] No silent freeze after 6+ switches; no page refresh required. * [x] Toggle MA/RSI after interval stress — overlays still work. * [ ] Switch pair — chart still loads and intervals remain responsive. ### Issue noticed The change of pairs on `/trade` always brings out an error from the page **Screen record:** This happens for all pairs across the `/trade` tab ![Screen Recording 2026-05-26 at 14.53.00.mov](/uploads/1ad6b21647f18452307182f92c1d7db6/Screen_Recording_2026-05-26_at_14.53.00.mov) cc: @PlasticDigits
PlasticDigits commented 2026-05-26 14:21:27 +00:00 (Migrated from gitlab.com)

mentioned in commit 7f37096604

mentioned in commit 7f370966045cb2eabd9c008928c61aa701e5a001
PlasticDigits commented 2026-05-26 14:21:37 +00:00 (Migrated from gitlab.com)

Fix landed on main (7f37096)

Root cause: The #148 interval fix applied placeholderData: keepPreviousData to the pair-keyed candles query (['candles', pairAddress, interval]). On pair switch, React Query kept the previous pair's OHLC as placeholder while fetching the new pair. That stale data was fed into a still-mounted PriceChartLightweightCanvas, triggering a lightweight-charts render crash (Cannot read properties of undefined (reading 'length')) and the route ErrorBoundary ("Something went wrong").

Changes:

Verification checklist (please confirm on /trade with LocalTerra + indexer)

  • Select a pair; open Price (USD) chart.
  • Click through 1m → 5m → 15m → 1h → 4h → 1d → 1w at least twice without refreshing.
  • After each click, candles/axis update to the new interval (may briefly show "Updating interval…" overlay).
  • No silent freeze after 6+ switches; no page refresh required.
  • Toggle MA/RSI after interval stress — overlays still work.
  • Switch pair — chart loads for the new pair (brief "Loading chart…" is OK); no "Something went wrong" ErrorBoundary.
  • After pair switch, click 1d (or another interval) — chart updates normally.

@brouie — please verify on your environment when you have a moment. Leaving the issue open until QA signs off.

/cc @totdking

## Fix landed on `main` (7f37096) **Root cause:** The #148 interval fix applied `placeholderData: keepPreviousData` to the pair-keyed candles query (`['candles', pairAddress, interval]`). On **pair switch**, React Query kept the **previous pair's OHLC** as placeholder while fetching the new pair. That stale data was fed into a still-mounted `PriceChartLightweightCanvas`, triggering a lightweight-charts render crash (`Cannot read properties of undefined (reading 'length')`) and the route **ErrorBoundary** ("Something went wrong"). **Changes:** - `priceChartCandlesPlaceholder.ts`: `keepPreviousCandlesForIntervalSwitch` — keeps prior rows **only when `pairAddress` is unchanged** (interval refetch); drops placeholder on pair change. - `PriceChart`: uses the selective placeholder helper; **`key={pairAddress}`** on `PriceChartLightweightCanvas` for a clean remount on pair switch. - Vitest: unit tests for placeholder helper + regression *remounts chart on pair switch and keeps interval switches responsive*. - Docs cross-links: [trade page price chart invariants](docs/frontend.md#trade-page-price-chart-invariants), [pair switch latency](docs/frontend.md#trade-page-pair-switch-latency), [`skills/AGENTS_FRONTEND_PRICE_CHART.md`](skills/AGENTS_FRONTEND_PRICE_CHART.md) invariant **#10**, [`skills/AGENTS_FRONTEND_TRADE_PAIR_SWITCH.md`](skills/AGENTS_FRONTEND_TRADE_PAIR_SWITCH.md) invariant **#5**. ## Verification checklist (please confirm on `/trade` with LocalTerra + indexer) - [ ] Select a pair; open Price (USD) chart. - [ ] Click through **1m → 5m → 15m → 1h → 4h → 1d → 1w** at least **twice** without refreshing. - [ ] After each click, candles/axis update to the new interval (may briefly show "Updating interval…" overlay). - [ ] No silent freeze after 6+ switches; no page refresh required. - [ ] Toggle MA/RSI after interval stress — overlays still work. - [ ] **Switch pair** — chart loads for the new pair (brief "Loading chart…" is OK); **no** "Something went wrong" ErrorBoundary. - [ ] After pair switch, click **1d** (or another interval) — chart updates normally. @brouie — please verify on your environment when you have a moment. Leaving the issue **open** until QA signs off. /cc @totdking
PlasticDigits commented 2026-05-26 14:31:26 +00:00 (Migrated from gitlab.com)

QA sign-off — closing #148

Shipped on origin/main: 7f37096 (pair-switch follow-up) on top of d04b0e9 (interval freeze fix). Local main matches origin/main; no open fix branches.

Two-part resolution

Commit Problem Fix
d04b0e9 Timeframe selector froze after ~5–6 interval switches keepPreviousData + interval loading overlay + chartInitIdRef — canvas stays mounted on interval refetch
7f37096 Pair switch crashed ErrorBoundary (Cannot read properties of undefined (reading 'length')) keepPreviousCandlesForIntervalSwitch — placeholder only when pairAddress unchanged; key={pairAddress} remounts canvas on pair change

Expected UX (invariants)

  • Interval switch (same pair): plot stays mounted; optional Updating interval… overlay (data-testid="price-chart-interval-loading").
  • Pair switch: brief Loading chart… is OK; no stale prior-pair candles; no route ErrorBoundary.

Verification (2026-05-26, LocalTerra + indexer + VITE_NETWORK=local)

  • Select a pair; open Price (USD) chart on /trade.
  • Click 1m → 5m → 15m → 1h → 4h → 1d → 1w twice — no silent freeze (@totdking).
  • Interval refetch overlay / axis updates (@totdking).
  • MA/RSI toggles after interval stress (@totdking).
  • Switch pair (EMBER/CORAL → EMBER/ONYX, EMBER/JADE) — no Something went wrong; chart canvas remounts; order ticket updates to new quote token.
  • Vitest: priceChartCandlesPlaceholder.test.ts + PriceChart.test.tsx (20 tests, incl. interval reuse + pair remount regressions).

/cc @totdking @brouie — reopen if pair switch or interval stress regresses on your stack.

## QA sign-off — closing #148 **Shipped on `origin/main`:** `7f37096` (pair-switch follow-up) on top of `d04b0e9` (interval freeze fix). Local `main` matches `origin/main`; no open fix branches. ### Two-part resolution | Commit | Problem | Fix | |--------|---------|-----| | `d04b0e9` | Timeframe selector froze after ~5–6 interval switches | `keepPreviousData` + interval loading overlay + `chartInitIdRef` — canvas stays mounted on **interval** refetch | | `7f37096` | Pair switch crashed ErrorBoundary (`Cannot read properties of undefined (reading 'length')`) | `keepPreviousCandlesForIntervalSwitch` — placeholder **only when `pairAddress` unchanged**; `key={pairAddress}` remounts canvas on pair change | ### Expected UX (invariants) - **Interval switch (same pair):** plot stays mounted; optional **Updating interval…** overlay (`data-testid="price-chart-interval-loading"`). - **Pair switch:** brief **Loading chart…** is OK; **no** stale prior-pair candles; **no** route ErrorBoundary. ### Verification (2026-05-26, LocalTerra + indexer + `VITE_NETWORK=local`) - [x] Select a pair; open Price (USD) chart on `/trade`. - [x] Click **1m → 5m → 15m → 1h → 4h → 1d → 1w** twice — no silent freeze (@totdking). - [x] Interval refetch overlay / axis updates (@totdking). - [x] MA/RSI toggles after interval stress (@totdking). - [x] **Switch pair** (EMBER/CORAL → EMBER/ONYX, EMBER/JADE) — no **Something went wrong**; chart canvas remounts; order ticket updates to new quote token. - [x] Vitest: `priceChartCandlesPlaceholder.test.ts` + `PriceChart.test.tsx` (20 tests, incl. interval reuse + pair remount regressions). ### Docs / agent cross-links - [docs/frontend.md § Trade page — price chart invariants](docs/frontend.md#trade-page-price-chart-invariants) - [docs/frontend.md § Trade page — pair switch latency](docs/frontend.md#trade-page-pair-switch-latency) - [`skills/AGENTS_FRONTEND_PRICE_CHART.md`](skills/AGENTS_FRONTEND_PRICE_CHART.md) invariant **#10** - [`skills/AGENTS_FRONTEND_TRADE_PAIR_SWITCH.md`](skills/AGENTS_FRONTEND_TRADE_PAIR_SWITCH.md) invariant **#5** /cc @totdking @brouie — reopen if pair switch or interval stress regresses on your stack.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-26 14:31:30 +00:00
PlasticDigits commented 2026-05-29 03:13:21 +00:00 (Migrated from gitlab.com)

mentioned in issue #211

mentioned in issue #211
PlasticDigits commented 2026-05-29 05:40:52 +00:00 (Migrated from gitlab.com)

mentioned in issue #225

mentioned in issue #225
PlasticDigits commented 2026-05-29 05:40:54 +00:00 (Migrated from gitlab.com)

marked as related to #225

marked as related to #225
PlasticDigits commented 2026-05-29 05:40:57 +00:00 (Migrated from gitlab.com)

mentioned in issue #226

mentioned in issue #226
PlasticDigits commented 2026-05-29 05:40:59 +00:00 (Migrated from gitlab.com)

marked as related to #226

marked as related to #226
PlasticDigits commented 2026-05-29 05:41:31 +00:00 (Migrated from gitlab.com)

mentioned in issue #228

mentioned in issue #228
PlasticDigits commented 2026-05-29 05:41:34 +00:00 (Migrated from gitlab.com)

marked as related to #228

marked as related to #228
PlasticDigits commented 2026-08-17 03:51:35 +00:00 (Migrated from gitlab.com)

mentioned in issue #543

mentioned in issue #543
PlasticDigits commented 2026-08-29 14:16:58 +00:00 (Migrated from gitlab.com)

mentioned in issue #705

mentioned in issue #705
PlasticDigits commented 2026-08-29 15:21:04 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1197

mentioned in merge request !1197
PlasticDigits commented 2026-09-01 08:14:37 +00:00 (Migrated from gitlab.com)

mentioned in issue #717

mentioned in issue #717
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#148
No description provided.