Skip to content

fix(frontend): reset left panel metadata on notebook switch - #950

Open
Hariharanpugazh wants to merge 3 commits into
kubeflow:mainfrom
Hariharanpugazh:fix/644-reset-left-panel-metadata-on-notebook-switch
Open

fix(frontend): reset left panel metadata on notebook switch#950
Hariharanpugazh wants to merge 3 commits into
kubeflow:mainfrom
Hariharanpugazh:fix/644-reset-left-panel-metadata-on-notebook-switch

Conversation

@Hariharanpugazh

Copy link
Copy Markdown

What this does

Fixes stale metadata in the Kale left panel when switching between notebooks.

Problem

When switching from one notebook to another, the left panel kept showing the
previous notebook's experiment, pipeline name, and description. The
notebook-load sequence in useNotebookLoader.loadNotebookPanel() awaits several
backend RPCs (getKfpUiHost, getNamespace, getExperiments) before it calls
setMetadata, and it never cleared state first. During that async window the
panel rendered stale values from the notebook we just left.

Fix

  • Reset the panel to fresh defaults synchronously at the start of every
    notebook switch, before any await, via a new resetForNotebookSwitch() in
    useNotebookMetadata. This also sets gettingExperiments, so the experiment
    field shows its existing "Loading..." state during the load instead of stale text.
  • Guard the async load with an isStale() check after each await: if the user
    switches notebooks again while a load is in flight, the late-resolving load
    bails out instead of clobbering the now-active notebook's metadata.
  • Clear the loading flag at the end of loadNotebookPanel so it resets on the
    non-backend path too.

Reset uses a fresh default metadata object rather than the shared
DefaultState.metadata reference, so it stays compatible with the
DefaultState freezing proposed in #868 (#643).

Testing

  • jlpm eslint:check — clean
  • prettier --check — clean
  • tsc --noEmit — clean
  • jest — passing

Manually verified by opening two notebooks with different metadata and switching
between them: the panel now resets/loads instead of showing the previous
notebook's values.

Related

When switching between notebooks, the left panel kept rendering the previous notebook's experiment, pipeline name, and description while the async loading RPCs (getKfpUiHost, getNamespace, getExperiments) were still pending. The metadata state was only updated after those awaits resolved, so stale values were visible during the gap.

Reset the panel to fresh defaults synchronously at the start of every notebook switch (before any await) and surface the existing experiment 'Loading...' state via gettingExperiments. Also guard the async load against completing after the user has switched again, so a late-resolving load cannot clobber the now-active notebook's metadata.

Fixes kubeflow#644

Signed-off-by: Hariharanpugazh <hariharanpugazh@gmail.com>
@google-oss-prow

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign ederign for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ada333 ada333 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @Hariharanpugazh I could not replicate the bug that is described in this PR - could you please share a video, or detailed instructions?

@Hariharanpugazh

Copy link
Copy Markdown
Author

Hi @ada333, thanks for taking a look! Here are detailed steps to reproduce.

Setup

Create two notebooks in the same Jupyter server, each with different Kale metadata:

  • notebook-a.ipynb → experiment exp-a, pipeline name pipeline-a, description Description A
  • notebook-b.ipynb → experiment exp-b, pipeline name pipeline-b, description Description B

Make sure Kale is enabled and the left panel is open.

Steps

  1. Open notebook-a.ipynb and wait for the Kale left panel to fully load you should see pipeline-a / Description A / exp-a.
  2. Without closing it, switch directly to notebook-b.ipynb.
  3. Watch the left panel during the load the window while getKfpUiHost / getNamespace / getExperiments are still resolving.

Expected: Panel clears to defaults (experiment shows Loading...), then populates with pipeline-b / Description B / exp-b.

Actual (before this fix): During the async load window the panel keeps showing the previous notebook's values (pipeline-a / Description A / exp-a) until the RPCs resolve.

Why it can be hard to hit

It's a race in loadNotebookPanel() - setMetadata is only called after several awaited backend RPCs, and state is never cleared first. If your backend responds very quickly, the stale window is tiny and easy to miss. To make it deterministic you can either throttle the network in DevTools, or temporarily add await new Promise(r => setTimeout(r, 2000)) before setMetadata in loadNotebookPanel() to widen the window, then switch notebooks and observe the stale values.

I'll follow up with a short screen recording if these steps don't reproduce it on your end.

The previous fix reset panel state on switch, but two deeper problems remained that caused metadata to leak between notebooks and the panel to hang when KFP was unreachable.

Root cause of the leak: the persistence effect wrote metadata to tracker.currentWidget, which is resolved when the effect runs (after paint), not when the edit was made. Switching tabs before the effect flushed wrote one notebook's metadata into another. The effect now targets the notebook the metadata was loaded from (loadedNotebookRef), so edits always save to the notebook they belong to.

Also: guard the metadata load so the loader's own setMetadata calls are not written back to the file (isLoadingRef), wrap the load in try/finally so the loading flag can never stay stuck, and stop backend RPC failures (unreachable KFP) from aborting the metadata load or freezing the panel.

Fixes kubeflow#644

Signed-off-by: Hariharanpugazh <hariharanpugazh@gmail.com>
@google-oss-prow google-oss-prow Bot added size/L and removed size/M labels Sep 2, 2026
@Hariharanpugazh

Copy link
Copy Markdown
Author

Thanks for taking a look, @ada333.

The original symptom is timing-sensitive, which is likely why it didn't reproduce for you on a fast KFP backend the stale-metadata window is very small.

While reproducing it locally I found a deeper and more serious variant of the same underlying issue: metadata could leak between notebooks.

Root cause: the metadata-persistence effect wrote to tracker.currentWidget, which is resolved when the effect runs (React runs effects after paint), not when the edit was made. If you switched notebook tabs before that effect flushed, one notebook's metadata got written into another notebook's .ipynb.

Fix: persist to the notebook the metadata was actually loaded from (tracked via a loadedNotebookRef) instead of the currently-active tab, so an edit always saves to the notebook it belongs to. I also:

  • guarded the load so the loader's own setMetadata calls aren't written back to the file,
  • wrapped the load in try/finally so the loading state can never get stuck, and
  • made the load resilient to an unreachable KFP so the panel no longer hangs on timeouts.

I've pushed these changes to this PR.

Repro for the original stale-metadata symptom:

  1. Create two notebooks, each with Kale enabled and different pipeline names/descriptions.
  2. Open notebook A, wait for the panel to populate.
  3. Switch to notebook B and watch the panel during the async load window (while getKfpUiHost / getNamespace / getExperiments resolve).

Expected: panel resets/loads B's values. Before the fix: it kept showing A's values during that window, and rapid switching could persist A's metadata onto B. To widen the window for a reliable repro, throttle the network in DevTools or add a temporary delay before setMetadata in loadNotebookPanel.

Extract the persistence decision into a pure resolveMetadataPersistence() helper (no runtime JupyterLab imports, so it is unit-testable in isolation) and add regression tests for kubeflow#644.

The key assertion guards the leak fixed in the previous commit: a metadata change is written to the notebook it was loaded from, never to the currently active tab. Also covers skipping while the loader is populating state, when metadata is unchanged, and when the owning notebook is missing or disposed.

Signed-off-by: Hariharanpugazh <hariharanpugazh@gmail.com>
@google-oss-prow google-oss-prow Bot added size/XL and removed size/L labels Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(frontend): Left panel shows stale metadata when switching between notebooks

2 participants