Bugfix: Theme persistence failing with MongoDB 500 error on POST /ap...
Documentation for Sessions
🐛 Bugfix: Theme persistence failing with MongoDB 500 error on POST /ap...
Date: 2026-02-25
Time: 20:18:21 UTC
Session: gspace1-141.9
Agent: backend
Confidence: 98%
Status: ✅ Documented
📋 Decision Context
Question:
Theme persistence failing with MongoDB 500 error on POST /api/spaces/:spaceId/themes — what is the root cause and fix?
Task: Fix theme color persistence 500 errors in backend-api
🎯 Decision Made
Chosen:
Strip both _id AND createdAt from $set payload to prevent $set/$setOnInsert field conflict
Options Considered:
- Strip _id from $set payload (already attempted in uncommitted changes but insufficient)
- Strip both _id AND createdAt from $set payload to prevent $set/$setOnInsert field conflict
- Remove $setOnInsert entirely and always write createdAt via $set
- Use replaceOne instead of updateOne to avoid operator conflicts
💭 Reasoning
ROOT CAUSE: When a theme document was fetched from MongoDB (e.g. via GET /api/themes/:id), it included createdAt (set on first insert). When that document was spread into normalizedTheme and then into $set, the createdAt field appeared in BOTH $set (from the spread) and $setOnInsert (explicitly set as a fallback for new docs). MongoDB forbids the same field path in both $set and $setOnInsert — this throws MongoServerError: 'Updating the path createdAt would create a conflict at createdAt'. The error was SILENT from the user's perspective because the frontend catchError handler swallowed it, logging only a warning. The fix destructures createdAt alongside _id before building the $set payload: const { _id, createdAt, ...payloadForSet } = normalizedTheme. This ensures createdAt is ONLY in $setOnInsert (set on insert, preserved on update). The same pattern was applied in ThemesService.upsertTheme() and SpacesService.saveThemeToSpace() for consistency. WHY OTHER OPTIONS ARE WORSE: (1) Removing $setOnInsert loses the creation timestamp on new documents. (2) replaceOne would overwrite the entire document including fields the frontend didn't send, causing data loss. EARLY WARNING SIGNAL: Any MongoDB upsert that spreads a document fetched from the DB into $set while also using $setOnInsert is vulnerable to this conflict. The pattern 'const { _id, createdAt, ...forSet } = doc' should become standard for all upsert operations.
📁 Files Involved
apis/backend-api/src/app/spaces/spaces.service.tsapis/backend-api/src/app/themes/themes.service.tsapis/backend-api/src/app/spaces/space-database.service.ts
🔗 Related
- Decision ID:
dev_1772050701534_46fo03y - Session: 141
- Workspace: gspace1
Auto-generated by MCP Smart Consolidation