fix: map curation assignment responses to camelCase to avoid approving undefined collection id - #3487
fix: map curation assignment responses to camelCase to avoid approving undefined collection id#3487RocioCM wants to merge 2 commits into
Conversation
…g undefined collection id
Approving a collection failed with a Postgres error ("invalid input
syntax for type uuid: undefined") whenever the curation had been
assigned or reassigned earlier in the same session. pushCuration and
updateCuration returned the raw server payload (snake_case
collection_id), which the assignee saga stored as a CollectionCuration;
the approval flow then read curation.collectionId as undefined and
requested PATCH /collections/undefined/curation.
Map both responses through fromRemoteCollectionCuration like the rest
of the curation methods, and dispatch the approval with collection.id
so the flow no longer depends on the stored object's shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWj6CmKCiRqgSEW9gn92ak
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
decentraland-bot
left a comment
There was a problem hiding this comment.
Review Summary
Verdict: ✅ Approve
This is a clean, well-targeted bug fix that correctly addresses the root cause. The changes are minimal, focused, and properly tested.
Root Cause Analysis
The bug occurred in this flow:
- Curator assigns a collection →
handleSetCurationCuratorAssigneeRequestsaga callspushCurationorupdateCuration pushCurationreturnedvoid, soupdatedCurationwasundefined;updateCurationreturned the raw snake_case API response (withcollection_idinstead ofcollectionId)setCollectionCurationAssigneeSuccess(collectionId, updatedCuration)dispatched a malformed/undefined curation into Redux state- Later, the approval flow read
curation.collectionId→undefined→ request sent to/collections/undefined/curation→ Postgres UUID parse error
Changes Reviewed
| File | Change | Assessment |
|---|---|---|
src/lib/api/builder.ts |
pushCuration now maps response through fromRemoteCollectionCuration, returns CollectionCuration instead of void |
✅ Correct — follows the same pattern as fetchCuration, pushItemCuration, etc. |
src/lib/api/builder.ts |
updateCuration now maps response through fromRemoteCollectionCuration, adds explicit return type |
✅ Correct — same pattern alignment |
src/modules/collection/sagas.ts |
Uses collection.id instead of curation.collectionId |
✅ Sound defensive fix — collection is already in scope and known-valid |
src/lib/api/builder.spec.ts |
Tests for both pushCuration and updateCuration response mapping |
✅ Good coverage of the fix |
Detailed Analysis
Correctness: The fix addresses both layers of the problem — the API methods now return properly-shaped objects (fixing the data at the source), and the saga uses collection.id as a defensive measure. Both pushCuration and updateCuration callers were verified:
handlePushCurationRequestignores the return value → no impacthandleSetCurationCuratorAssigneeRequeststores the return value asupdatedCuration→ now receives a properly mappedCollectionCuration- Existing saga tests already mock these methods to return camelCase
CollectionCurationobjects, consistent with the new return types
API contract: The return type changes (void → CollectionCuration and untyped → CollectionCuration) are backward-compatible. Callers that previously ignored the return value continue to work.
Security: No concerns — no new endpoints, no auth changes, no user input handling changes. The fix actually improves security hygiene by preventing undefined from being interpolated into URL paths.
Test coverage: Tests verify the snake_case → camelCase mapping for both methods. The test structure (shared remoteCuration / expectedCuration fixtures with beforeEach mock setup) is clean.
Git conventions: PR title follows fix: <summary> format ✅, branch follows fix/<summary> format ✅
No P0 or P1 findings.
Reviewed by Jarvis 🤖 · Requested by RocioCM via GitHub
| @@ -1105,8 +1109,12 @@ export class BuilderAPI extends BaseAPI { | |||
| return this.request('patch', `/collections/${collectionId}/curation`, { params: { curation: { status } } }) | |||
There was a problem hiding this comment.
[P2] Pre-existing observation: updateCurationStatus (line ~1109) also returns the raw this.request(...) response without mapping through fromRemoteCollectionCuration. This is currently safe because its callers (handleApproveCurationRequest, handleRejectCurationRequest) don't use the return value — they just dispatch success with the collectionId they already have. But for consistency with the rest of the curation API surface, it might be worth aligning it in a follow-up. Not blocking.
- Map updateCurationStatus response through fromRemoteCollectionCuration for consistency with the rest of the curation API surface Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WWj6CmKCiRqgSEW9gn92ak
Coverage Report for CI Build 33517308160Coverage increased (+0.02%) to 53.547%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats💛 - Coveralls |
What
invalid input syntax for type uuid: "undefined"after the curation was assigned or reassigned during the same session.Why
When a curator assigned a collection (e.g. to themselves) and later approved it without reloading the page, the approval flow sent the curation update to
/collections/undefined/curation, surfacing a Postgres uuid error and aborting the flow — even though the item entities had already deployed successfully.How to test