Skip to content

fix: map curation assignment responses to camelCase to avoid approving undefined collection id - #3487

Open
RocioCM wants to merge 2 commits into
masterfrom
fix/collection-curation-approval-undefined-uuid
Open

fix: map curation assignment responses to camelCase to avoid approving undefined collection id#3487
RocioCM wants to merge 2 commits into
masterfrom
fix/collection-curation-approval-undefined-uuid

Conversation

@RocioCM

@RocioCM RocioCM commented Sep 1, 2026

Copy link
Copy Markdown
Member

What

  • Approving a collection no longer fails with invalid input syntax for type uuid: "undefined" after the curation was assigned or reassigned during the same session.
  • The curation assignment API responses are now returned in the same shape as every other curation fetch, so the state no longer holds a malformed curation after assigning.

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

  1. As a curator, open the Curation page and assign a pending collection to yourself.
  2. Without reloading, open the collection's review page and click Approve, completing the upload step.
  3. The flow should reach the success screen and the curation should be approved, with no uuid error modal.

…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
@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
builder Ready Ready Preview Sep 1, 2026 2:08pm UTC

Request Review

@decentraland-bot decentraland-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. Curator assigns a collection → handleSetCurationCuratorAssigneeRequest saga calls pushCuration or updateCuration
  2. pushCuration returned void, so updatedCuration was undefined; updateCuration returned the raw snake_case API response (with collection_id instead of collectionId)
  3. setCollectionCurationAssigneeSuccess(collectionId, updatedCuration) dispatched a malformed/undefined curation into Redux state
  4. Later, the approval flow read curation.collectionIdundefined → 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:

  • handlePushCurationRequest ignores the return value → no impact
  • handleSetCurationCuratorAssigneeRequest stores the return value as updatedCuration → now receives a properly mapped CollectionCuration
  • Existing saga tests already mock these methods to return camelCase CollectionCuration objects, consistent with the new return types

API contract: The return type changes (voidCollectionCuration 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

Comment thread src/lib/api/builder.ts Outdated
@@ -1105,8 +1109,12 @@ export class BuilderAPI extends BaseAPI {
return this.request('patch', `/collections/${collectionId}/curation`, { params: { curation: { status } } })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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
@coveralls

coveralls commented Sep 1, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 33517308160

Coverage increased (+0.02%) to 53.547%

Details

  • Coverage increased (+0.02%) from the base build.
  • Patch coverage: 2 uncovered changes across 1 file (5 of 7 lines covered, 71.43%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
src/lib/api/builder.ts 6 4 66.67%
Total (2 files) 7 5 71.43%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 13377
Covered Lines: 7781
Line Coverage: 58.17%
Relevant Branches: 6019
Covered Branches: 2605
Branch Coverage: 43.28%
Branches in Coverage %: Yes
Coverage Strength: 37.35 hits per line

💛 - Coveralls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants