Skip to content

[Bug]: Mobile draft-save failure shows Retry and blocks Send after successful attachment upload #21097

Closed

Description

@trahane

Before submitting

  • I searched existing issues and did not find a duplicate of this failure path.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/mobile

Steps to reproduce

Deterministic reproduction on a disposable Android development client:

  1. Run upstream commit 16918b57d6754d6f145e9b6367c825aa31a740da with an isolated backend. Pair the native client, open an existing thread, and enter some composer text so its draft directory exists.
  2. Make only the app's files/composer-drafts directory unwritable, changing its mode from 700 to 500. Keep the outbox directory writable. This induces a real draft-write failure without a transport failure. For the debug package, the test used adb -s <serial> shell run-as com.t3tools.t3code.dev chmod 500 files/composer-drafts.
  3. Attach a small PNG through the native Files picker. The server accepts the upload with HTTP 204; saving composer-drafts/drafts.json then fails.
  4. Observe Retry on the attachment thumbnail and disabled Send. Retry repeats the failure while draft storage remains unwritable. Restore the original directory mode and contents after testing.

Expected behavior

A draft-storage failure should not prevent the user from queuing the attachment through the existing durable outbox when the local file is available and outbox storage is healthy. Sending must still wait for a durable outbox entry and valid uploaded attachment reference; a failed draft save should not be represented as successful.

Actual behavior

The background worker successfully uploads the image, then its flushComposerDrafts() callback rejects with ComposerDraftPersistenceError. The preparation cleanup releases the new pending upload. The queue marks the attachment failed, and the composer blocks Send as though the file transfer itself failed.

The original report was an Android installed release APK: pasting a screenshot from Photos reached 100%, then showed Retry on the thumbnail and grayed out Send. Rapidly pressing Retry and Send sometimes delivered the image. The original phone's exact exception is unknown; the controlled reproduction above establishes this specific failure path rather than proving every similar symptom has the same cause.

Impact

Major degradation or frequent failure: the affected message cannot be sent normally while draft persistence is failing, despite a working server connection and independently writable outbox.

Version or commit

Reproduced on upstream 16918b57d6754d6f145e9b6367c825aa31a740da. Fix comparison: 55b6036e96a67baa928f0fdd0da83bbc08604f18 in #21084.

Environment

Android 17 emulator; upstream debug package com.t3tools.t3code.dev; React Native 0.88.0 / Expo 58.0.14; local isolated backend and Metro. A real 3,406-byte PNG was selected through Files. A controlled provider peer avoided real inference. iOS, a release build with the fix, and the original Photos clipboard source were not verified in this controlled test.

Logs or stack traces

Observed sequence: upload HTTP 204, followed by ComposerDraftPersistenceError for composer-drafts/drafts.json. The native accessibility snapshot reports the action “Retry or remove the failed attachment” as disabled. With #21084, Queue is enabled, a direct tap persists the outbox and re-uploads, and the delivered server image matches the source bytes exactly.

Screenshots, recordings, or supporting files

Baseline: Retry thumbnail and disabled Send

18-second baseline recording:

baseline-before.mp4

The baseline was recaptured after restoring unmodified source; the delivered image above the composer is prior test context, not the currently failed draft. Full before/after recordings, persistence checks, and 224 focused test results are in #21084.

Workaround

No reliable user-facing workaround established. Racing Retry and Send sometimes worked in the original report. Restoring draft-directory permissions removes the deliberately injected test fault.

Related work

Proposed fix: #21084. This is distinct from #1304 (old web/desktop premature draft verification) and #11427 (iOS HEIC import/preview freeze).

Filed with GPT-6 Astra (xhigh), with search and native verification by GPT-6.1 Sol (xhigh), using the Codex harness in Harbordex.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions