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 — signed → PUT (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:
- 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).
- Select a file and attempt to upload it.
- 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.
Describe the bug
Uploading a file inside the add-on fails. The file bytes upload to object storage successfully (the
PUTto the bucket returns200), but the subsequent "create upload entry" request —POST /api/uploads— fails with400:{"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 populateduser.id, the id isundefined;JSON.stringifysilently drops the key, and the backend Zod schema (packages/send/backend/src/routes/uploads.ts) rejects the body as missingownerId.Because the failure is deterministic, the upload retry loop (up to 5 attempts/part) re-runs the entire block —
signed→PUT(200) →uploads(400) — over and over. Everyapi.callalso triggers a token refresh (getAccessToken()→signinSilent()), so the network tab fills with a storm of repeatedtoken/userinfo/signed/uploads(400) requests.To Reproduce
Steps to reproduce the behavior:
user.idhas not been populated from the backend session (GET users/mewas skipped or failed at load).PUTto the object store succeeds (200), thenPOST /api/uploadsreturns 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/uploadsreturns400 Invalid request bodywithownerId"Required" (undefined). The retry loop and per-call token refresh produce a large volume oftoken/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
Additional context
Fixed on branch
fix/addon-expired-token-closes-send-tabsby adding a self-healing guard inuploadItem(packages/send/frontend/src/apps/send/stores/folder-store.ts): before uploading, ifuser.idis empty it callspopulateFromBackend(), and if the id is still empty it aborts with a clear error instead of sending an emptyownerId. Because theUploaderholds the same shared reactiveuserobject, re-populating also fixesthis.user.idinsidedoUpload.The underlying trigger for the empty
user.idis related to the OIDC silent-refresh churn tracked separately (see companion issue): a failed/skippedGET users/meat load leaves the reactive user store unpopulated.