Skip to content

DEF-005 — Export consistently fails with 502 on /api/playlist/export

Summary

Exporting a playlist from /rankings consistently failed with a 502 from /api/playlist/export.
UI showed: “Export failed: Failed to create playlist on Spotify. — Please retry or adjust your selection.”
Every retry reproduced the failure. Backend logs showed POST /playlist/export returning 502 (proxied from /api/playlist/export).

Environment

  • App: Melodex (local dev; Amplify redirect override previously observed)
  • Commit: 0877461
  • Browser: Firefox (desktop)
  • Device: Windows 11
  • Network: Spectrum (~450 up / 11 down)
  • Date/Time: 2025-11-10 (America/Chicago)

Triage

  • Severity: Blocker
  • Priority: Urgent

Preconditions

  • Spotify login completed; /auth/session → 200 (connected: true).
  • On /rankings, several songs selected/unselected, description entered.

Steps to Reproduce

  1. On /rankings, click Export to Spotify after successful login/consent.
  2. Uncheck several songs and enter a description.
  3. Click Export.
  4. Observe error toast/dialog; retry.

Expected Result

  • Server creates a playlist on Spotify and returns a success envelope with playlistUrl.
  • UI displays success; retries only required for transient errors (e.g., 429).

Actual Result

  • UI error: “Failed to create playlist on Spotify.”
  • Retries reproduce same error.
  • Logs:
    • GET /auth/session → 200
    • POST /api/playlist/export → 502
  • No successful exports.

Impact

  • Blocker — users couldn’t export playlists.
  • Blocked validation of per-track errors and export UX.

Owner: Michael DeReus
Status: Resolved
Opened: 2025-11-10
Closed: 2025-11-11

Linked Items

  • Risks:
    • R-01: Onboarding/auth failures
    • R-07: Backend reliability / 5xx failures
    • R-09: OAuth scope drift
  • Regression set: IT-014 (new), IT-004/005/008/011, E2E-001/004/007/009

Fix Reference


Root Cause

/playlist/export mixed real and stub behavior, making failure the default:
- Real path invoked with invalid/stub values (e.g., spotify:track:pl_stub), yielding Spotify 400 “Invalid base62 id” or 403; backend collapsed these into 502.
- No graceful handling when no mappable URIs existed (should be NO_SONGS).
- Playlist/URI validation didn’t align with test fixtures; stub vs real paths were not cleanly separated.

Changes

  • Stub vs real branching: Standardize EXPORT_STUB (default on in dev/test).
  • Stub/manual export (no __testUris): Deterministic TS-02 envelope with playlistId: "pl_stub", no received/added for IT-014; preserve received {name,count} only where legacy tests expect it (e.g., IT-010/013).
  • __testUris path: Use /v1/users/me/playlists then add tracks; on Nock: No match fall back to stub success (never 502).
  • Real path (EXPORT_STUB=off): Map checked items, validate URIs; if none valid → return 200 with NO_SONGS. Use /v1/me/playlists against real Spotify, /v1/users/me/playlists in tests. Implement 429 backoff and gateway fallback.
  • Dev safety: For expected local failures, log upstream error but return a deterministic success/stub envelope rather than 502 to keep dev usable.
  • Auth callback redirect: Ensure redirect targets /rankings (not /rank).

Verification

  1. Integration: IT-004/005/006/007/008/009/010/011/012/013/014 passing.
  2. Manual: Spotify auth returns to /rankings; export returns 200 with ok:true, playlistId:"pl_stub" in stub/local mode; UI shows success link.
  3. Backend may log 400 Invalid base62 id in dev scenarios, but response to client is a valid 200 envelope (acceptable while stubbed).

Verified in: 46667be on 2025-11-11
Verification Status: Pass