Skip to content

Uploading a file in the add-on fails — POST /api/uploads returns 400 (ownerId empty) #950

Description

@aaspinwall

Describe the bug

Uploading a file inside the add-on fails. The file bytes upload to object storage successfully (the PUT to the bucket returns 200), but the subsequent "create upload entry" request — POST /api/uploads — fails with 400:

{"message":"Invalid request body","errors":[{"code":"invalid_type","expected":"string","received":"undefined","path":["ownerId"],"message":"Required"}]}

The frontend sends ownerId: this.user.id (packages/send/frontend/src/lib/upload.ts). When the user session has not populated user.id, the id is undefined; JSON.stringify silently drops the key, and the backend Zod schema (packages/send/backend/src/routes/uploads.ts) rejects the body as missing ownerId.

Because the failure is deterministic, the upload retry loop (up to 5 attempts/part) re-runs the entire block — signedPUT (200) → uploads (400) — over and over. Every api.call also triggers a token refresh (getAccessToken()signinSilent()), so the network tab fills with a storm of repeated token / userinfo / signed / uploads (400) requests.

To Reproduce

Steps to reproduce the behavior:

  1. Open Send inside the add-on in a state where user.id has not been populated from the backend session (GET users/me was skipped or failed at load).
  2. Select a file and attempt to upload it.
  3. Observe in the network tab: PUT to the object store succeeds (200), then POST /api/uploads returns 400, repeated many times as the retry loop runs.

Expected behavior

The upload succeeds. If the session is missing a user id, the app should re-hydrate the user (or fail fast with a clear message) rather than firing a request that is guaranteed to 400 and hammering it via the retry loop.

Actual behavior

POST /api/uploads returns 400 Invalid request body with ownerId "Required" (undefined). The retry loop and per-call token refresh produce a large volume of token / userinfo / signed / uploads (400) requests, and the upload never completes.

Screenshots

Network tab shows repeating token (200), userinfo (200), signed (200), PUT (200), uploads (400) cycles.

System

  • OS: macOS
  • Browser Version: Thunderbird (add-on / system add-on build)

Additional context

Fixed on branch fix/addon-expired-token-closes-send-tabs by adding a self-healing guard in uploadItem (packages/send/frontend/src/apps/send/stores/folder-store.ts): before uploading, if user.id is empty it calls populateFromBackend(), and if the id is still empty it aborts with a clear error instead of sending an empty ownerId. Because the Uploader holds the same shared reactive user object, re-populating also fixes this.user.id inside doUpload.

The underlying trigger for the empty user.id is related to the OIDC silent-refresh churn tracked separately (see companion issue): a failed/skipped GET users/me at load leaves the reactive user store unpopulated.

Metadata

Metadata

Assignees

Labels

SendThis is an issue with Thunderbird Send's backend/frontend components

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions