{"record":{"id":"596367719e70f298","repo":"payloadcms/payload","slug":"failed-to-retrieve-array-of-joins-for-slug-in-c","errorCode":null,"errorMessage":"Failed to retrieve array of joins for ${slug} in collectio ${collection}","messagePattern":"Failed to retrieve array of joins for (.+?) in collectio (.+?)","errorType":"http","errorClass":"APIError","httpStatus":500,"severity":"error","filePath":"packages/db-mongodb/src/utilities/buildJoinAggregation.ts","lineNumber":263,"sourceCode":"          $gt: [{ $size: `$${as}.docs` }, limitJoin || Number.MAX_VALUE],\n        },\n      },\n    })\n\n    aggregate.push({\n      $set: {\n        [`${as}.docs`]: {\n          $slice: [`$${as}.docs`, ...sliceValue],\n        },\n      },\n    })\n  }\n\n  for (const slug of Object.keys(joinConfig)) {\n    const joinsList = joinConfig[slug]\n\n    if (!joinsList) {\n      throw new APIError(`Failed to retrieve array of joins for ${slug} in collectio ${collection}`)\n    }\n\n    for (const join of joinsList) {\n      const projectionPath = versions ? `version.${join.joinPath}` : join.joinPath\n      if (projection && !projection[projectionPath]) {\n        continue\n      }\n\n      if (joins?.[join.joinPath] === false) {\n        continue\n      }\n\n      const collectionConfig = adapter.payload.collections[join.field.collection as string]?.config\n\n      if (!collectionConfig) {\n        throw new APIError(\n          `Collection config for ${join.field.collection.toString()} was not found`,\n        )","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/db-mongodb/src/utilities/buildJoinAggregation.ts#L245-L281","documentation":"Thrown while iterating `Object.keys(joinConfig)` when `joinConfig[slug]` is nullish. NOTE the message has a typo ('collectio') and interpolates `collection`. Normally near-unreachable because keys come from the object itself, but possible if a sanitized join config contains an explicit `null`/`undefined` value under a key.","triggerScenarios":"A sanitized join config shaped like `{ somePath: null }` — a key exists but its value is nullish, so the inner `for (const join of joinsList)` would fail.","commonSituations":"Hand-edited or programmatically-malformed sanitized config; a partial migration that left null entries; a bug in join sanitization producing null values for a path.","solutions":["Inspect the collection's sanitized `joins` object for null/undefined values.","Re-run sanitization by restarting the process so config is rebuilt cleanly.","Verify each join field definition is complete and valid.","If reproducing, report with the sanitized config dump — this path is normally defensive."],"exampleFix":"// malformed sanitized config\n{ joins: { author: null } }\n// fix: ensure join is fully defined or removed\n{ joins: { author: [{ field: {...}, ... }] } }","handlingStrategy":"validation","validationCode":"function assertJoinsList(joinConfig, slug, collection) {\n  const list = joinConfig[slug]\n  if (!list) throw new Error(`Null join list for ${slug} in ${collection}`)\n  return list\n}","typeGuard":"const isValidJoinsEntry = (joinConfig, slug) =>\n  Boolean(joinConfig && joinConfig[slug])","tryCatchPattern":"try { await payload.find({ collection, joins }) }\ncatch (e) { if (/Failed to retrieve array of joins/.test(e.message)) dumpSanitizedJoins(collection) else throw e }","preventionTips":["Don't hand-edit the sanitized join config — let init rebuild it.","Restart after config changes so sanitization runs cleanly.","Report reproductions of this near-unreachable path with a config dump."],"tags":["mongodb","joins","config","typo"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}