Skip to content

[BUG] Scans polling can overwrite current view with stale responses #415

@eshaanag

Description

@eshaanag

Summary

The Scans page polling can overlap with manual/filter/page refreshes. If an older request resolves after a newer one, the stale response can overwrite the latest task list and pagination state.

I would like to work on this under GSSoC if maintainers agree with the scope. Please assign this issue to me.

Why this matters

The Scans page is used to monitor task state. Under a slow backend or flaky network, users can switch filters or pages and still see results from a previous request because loadTasks() does not cancel in-flight requests or guard against stale responses.

Reproduction steps

  1. Open the Scans page.
  2. Let the initial /tasks request remain slow.
  3. Change the status filter or page, which triggers a newer /tasks request.
  4. Let the older request resolve after the newer request.
  5. The older response can call setTasks() and setTotal() after the newer state has already rendered.

Expected behavior

Only the latest Scans request should update task list and pagination state. Older in-flight requests should be cancelled or ignored.

Actual behavior

Every completed request updates React state, regardless of whether it is still the latest request for the current filter/page.

Scope

  • Suggested files or directories:
    • frontend/src/pages/Scans.tsx:67
    • frontend/src/pages/Scans.tsx:81
    • frontend/src/pages/Scans.tsx:102
    • frontend/src/pages/Scans.tsx:109
    • frontend/src/pages/Scans.tsx:111
  • Related route, page, component, or script:
    • Scans page polling
    • GET /api/v1/tasks

Evidence

The page starts interval polling and calls loadTasks() again whenever filter or page changes. The fetch path updates state directly:

const res = await fetch(`${API_BASE}/tasks?${params.toString()}`);
const data = await res.json();
setTasks(data.tasks || []);
setTotal(data.pagination.total_items);

There is no AbortController, request sequence guard, or mounted-state guard.

Environment

  • OS: Any
  • Browser: Any
  • Python Version: N/A
  • Node Version: 20+ project target
  • Docker Version: N/A

Definition of done

  • In-flight Scans list requests are cancelled or ignored when superseded
  • Stale responses cannot overwrite the latest filter/page data
  • Polling cleanup still works on unmount and tab visibility changes
  • Regression tests cover out-of-order responses

Additional context

Likely difficulty: intermediate because it touches async UI polling and race-condition behavior. I am not applying labels directly because maintainers/admins handle scoring labels.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions