Offline capture rejected by the server retries forever with no user-visible reason #108

Closed
opened 2026-07-15 19:52:54 +00:00 by claude-bot · 1 comment
Contributor

Severity: Medium · Confidence: High · Effort: S · Category: ui

Evidence

  • app/src/hooks/useOfflineQueue.ts:83-104 - sync(): on res.ok === false (e.g. 400 validation or 401 after session expiry) the item is neither removed nor flagged; the catch only breaks for thrown/network errors.
  • app/src/components/layout/QuickCapture.tsx:406-411 - only a generic "N offline captures pending" banner.

Problem
A queued offline capture rejected by the server (content too long, session expired) is retried on every sync() (each 'online' event) indefinitely, with no error state exposed - the pending banner never resolves and never explains why.

Impact
A permanently stuck capture the user can neither see the reason for nor clear. Data limbo.

Fix
On !res.ok, capture the response and surface a per-item "failed to sync - " state, with a way to view/discard/edit the stuck item.

Acceptance criteria

  • A server-rejected offline capture surfaces a reason and can be cleared/edited.
  • It stops silently retrying forever.

Filed from the 2026-07-15 codebase audit. Full report: docs/.internal/report-2026-07-15.md (gitignored).

**Severity:** Medium · **Confidence:** High · **Effort:** S · Category: ui **Evidence** - `app/src/hooks/useOfflineQueue.ts:83-104` - `sync()`: on `res.ok === false` (e.g. 400 validation or 401 after session expiry) the item is neither removed nor flagged; the `catch` only `break`s for thrown/network errors. - `app/src/components/layout/QuickCapture.tsx:406-411` - only a generic "N offline captures pending" banner. **Problem** A queued offline capture rejected by the server (content too long, session expired) is retried on every `sync()` (each 'online' event) indefinitely, with no error state exposed - the pending banner never resolves and never explains why. **Impact** A permanently stuck capture the user can neither see the reason for nor clear. Data limbo. **Fix** On `!res.ok`, capture the response and surface a per-item "failed to sync - <reason>" state, with a way to view/discard/edit the stuck item. **Acceptance criteria** - [ ] A server-rejected offline capture surfaces a reason and can be cleared/edited. - [ ] It stops silently retrying forever. --- _Filed from the 2026-07-15 codebase audit. Full report: `docs/.internal/report-2026-07-15.md` (gitignored)._
Author
Contributor

A server-rejected offline capture (400/401) is now captured with its reason, flagged so auto-sync skips it (no more infinite silent retry), and surfaced in a panel with per-item Retry (e.g. after re-login) and Discard. pendingCount excludes flagged items so the banner can reach zero. Covered by new tests (no-auto-retry, retry, discard).

Shipped in 59e4fdd (test fix 6561f9a), part of the v7.3.0 milestone. Verified on dev (v7.2.1-3-g6561f9a): app suite 65/65 and api suite 268/268 green on the dev server; the one CI red was the known runner flake (iac#159), not this change.

A server-rejected offline capture (400/401) is now captured with its reason, flagged so auto-sync **skips** it (no more infinite silent retry), and surfaced in a panel with per-item **Retry** (e.g. after re-login) and **Discard**. `pendingCount` excludes flagged items so the banner can reach zero. Covered by new tests (no-auto-retry, retry, discard). Shipped in `59e4fdd` (test fix `6561f9a`), part of the v7.3.0 milestone. Verified on dev (`v7.2.1-3-g6561f9a`): app suite 65/65 and api suite 268/268 green on the dev server; the one CI red was the known runner flake (iac#159), not this change.
Sign in to join this conversation.
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
rbrooks/TeaLeaves#108
No description provided.