{"record":{"id":"1bedf3e183bc2510","repo":"payloadcms/payload","slug":"unexpected-array-of-collectionslug-parent-must-be","errorCode":null,"errorMessage":"Unexpected array of collectionSlug, parent must be provided","messagePattern":"Unexpected array of collectionSlug, parent must be provided","errorType":"exception","errorClass":"APIError","httpStatus":500,"severity":"error","filePath":"packages/ui/src/utilities/buildTableState.ts","lineNumber":140,"sourceCode":"\n  const collectionPreferences = await upsertPreferences<CollectionPreferences>({\n    key: preferencesKey,\n    req,\n    value: {\n      columns: columnsFromArgs,\n      limit: isNumber(query?.limit) ? Number(query.limit) : undefined,\n      sort: query?.sort as string,\n    },\n  })\n\n  let data: PaginatedDocs = dataFromArgs\n\n  // lookup docs, if desired, i.e. within `join` field which initialize with `depth: 0`\n\n  if (!data?.docs || query) {\n    if (Array.isArray(collectionSlug)) {\n      if (!parent) {\n        throw new APIError('Unexpected array of collectionSlug, parent must be provided')\n      }\n\n      const select = {}\n      let currentSelectRef = select\n\n      const segments = parent.joinPath.split('.')\n\n      for (let i = 0; i < segments.length; i++) {\n        currentSelectRef[segments[i]] = i === segments.length - 1 ? true : {}\n        currentSelectRef = currentSelectRef[segments[i]]\n      }\n\n      const joinQuery: { limit?: number; page?: number; sort?: string; where?: Where } = {\n        sort: query?.sort as string,\n        where: query?.where,\n      }\n\n      if (query) {","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/ui/src/utilities/buildTableState.ts#L122-L158","documentation":"Thrown by buildTableState when `collectionSlug` is an array but `parent` is omitted. The array form is reserved for polymorphic join tables (a join whose target resolves to multiple collections); resolving the rows requires the parent document plus its `joinPath` so the table can be scoped to that single relationship. Without `parent`, the server has no way to select or join the correct documents.","triggerScenarios":"Invoking the table-state server function with an array `collectionSlug` and no `parent.collectionSlug`/`parent.id`/`parent.joinPath`; a custom client component forwarding multiple collection slugs for what is actually a single-collection table; a regression in join rendering that drops the `parent` prop.","commonSituations":"Custom relationship/join UIs that reuse buildTableState incorrectly, refactors of join field rendering that stop forwarding `parent`, client code sending an array where the server expects a single slug.","solutions":["When passing an array of collection slugs, also pass a `parent` object containing `collectionSlug`, `id`, and `joinPath`.","If you are rendering a single collection's table, pass `collectionSlug` as a string, not an array.","Audit custom List/Table overrides to confirm they forward the `parent` prop for join tables.","Constrain the public caller's types so an array `collectionSlug` requires `parent`."],"exampleFix":"// before\nbuildTableState({ collectionSlug: ['posts', 'pages'] })\n\n// after\nbuildTableState({\n  collectionSlug: ['posts', 'pages'],\n  parent: { collectionSlug: 'users', id, joinPath: 'related' },\n})","handlingStrategy":"validation","validationCode":"if (Array.isArray(collectionSlug) && !parent) {\n  throw new Error(\n    'parent (collectionSlug, id, joinPath) is required when collectionSlug is an array',\n  )\n}\n// only then call buildTableState","typeGuard":"function isValidJoinTableArgs(\n  collectionSlug: unknown,\n  parent: unknown,\n): parent is { collectionSlug: string; id: number | string; joinPath: string } {\n  if (!Array.isArray(collectionSlug)) return true // single slug needs no parent\n  return (\n    !!parent &&\n    typeof parent === 'object' &&\n    typeof (parent as any).collectionSlug === 'string' &&\n    (parent as any).id !== undefined &&\n    typeof (parent as any).joinPath === 'string'\n  )\n}","tryCatchPattern":null,"preventionTips":["Treat an array `collectionSlug` as join-only and always pair it with a `parent` object.","Type the public caller so array `collectionSlug` statically requires `parent`.","Audit custom List/Table overrides each release to confirm they forward `parent` for join tables.","Add a unit test that buildTableState rejects an array collectionSlug without parent."],"tags":["table-state","joins","validation","invariant"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}