Skip to content

fix(extract): handle singleton collections in getCollectionItems (#144)#146

Open
zerothirteenstudio wants to merge 1 commit into
directus-labs:mainfrom
zerothirteenstudio:fix/singleton-extract-crash
Open

fix(extract): handle singleton collections in getCollectionItems (#144)#146
zerothirteenstudio wants to merge 1 commit into
directus-labs:mainfrom
zerothirteenstudio:fix/singleton-extract-crash

Conversation

@zerothirteenstudio

Copy link
Copy Markdown

Fixes #144.

extract (with content) crashes when the source instance has singleton collections, because getCollectionItems assumes readItems() always returns an array:

const response = (await api.client.request(readItems(collection, {limit, page}))) as Record<string, unknown>[]
items.push(...response)            // singleton → object, not iterable
if (response.length < PAGE_SIZE) break

For a singleton, the SDK resolves to the single item object, so ...response throws Spread syntax requires ...iterable[Symbol.iterator] to be a function and response.length is undefined. The extract aborts at the first singleton (alphabetically) and writes no content for it or any collection after it.

Fix

Guard the non-array response — wrap a singleton object in an array:

const rows = Array.isArray(response) ? response : response ? [response] : []
items.push(...rows)
if (rows.length < PAGE_SIZE) break

Verification

Single-file change; non-singleton collections keep the existing array path unchanged.

@alexvdvalk

Copy link
Copy Markdown
Collaborator

This writes the output into an array in the json which may impact the loading function too

…Items

A singleton returns a single object; spreading it crashes (directus-labs#144). Return the object as-is so
the file stays an object — loadSingletons reads it back as an object, so wrapping it in an
array silently drops the singleton's data on apply. getDataFromCollection normalises to an
array for the relation-stripping passes but writes the original shape.
@zerothirteenstudio

Copy link
Copy Markdown
Author

You're completely right. I went and checked on a real instance and it's actually a bit worse than the crash: with the array wrap, loadSingletons reads the file back as an object, so the array comes through as updateSingleton(collection, {0: {…}}) and the singleton's data just quietly gets dropped on apply, no error at all.

So I've switched it to write the singleton as an object instead, and normalise to an array only for the relation-stripping pass. On a test instance that gives a clean extract (the singleton as an object, array collections untouched) and the apply round-trips fine.

Does that approach look right to you, or would you rather handle singletons a different way, like detecting them and using readSingleton?

@zerothirteenstudio
zerothirteenstudio force-pushed the fix/singleton-extract-crash branch from 59e5542 to a586e98 Compare June 11, 2026 17:24
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.

extract crashes on singleton collections (getCollectionItems spreads a non-array response)

2 participants