{"record":{"id":"d774135f5e7e9c83","repo":"transloadit/uppy","slug":"failed-to-get-a-media-items","errorCode":null,"errorMessage":"Failed to get a media items","messagePattern":"Failed to get a media items","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@uppy/core/src/companion-client/googlePicker.ts","lineNumber":424,"sourceCode":"  accessToken,\n  pickingSession,\n  signal,\n}: {\n  accessToken: string\n  pickingSession: PickingSession\n  signal: AbortSignal\n}) {\n  const headers = getAuthHeader(accessToken)\n\n  let pageToken: string | undefined\n  let mediaItems: MediaItem[] = []\n  do {\n    const pageSize = 100\n    const response = await fetch(\n      `https://photospicker.googleapis.com/v1/mediaItems?${new URLSearchParams({ sessionId: pickingSession.id, pageSize: String(pageSize), ...(pageToken && { pageToken }) }).toString()}`,\n      { headers, signal },\n    )\n    if (!response.ok) throw new Error('Failed to get a media items')\n    const {\n      mediaItems: batchMediaItems,\n      nextPageToken,\n    }: { mediaItems: MediaItem[]; nextPageToken?: string } =\n      await response.json()\n    pageToken = nextPageToken\n    mediaItems.push(...batchMediaItems)\n  } while (pageToken)\n\n  // Filter out items that aren't fully processed or ready\n  mediaItems = mediaItems.flatMap((i) =>\n    i.type === 'PHOTO' ||\n    (i.type === 'VIDEO' &&\n      i.mediaFile.mediaFileMetadata.videoMetadata.processingStatus === 'READY')\n      ? [i]\n      : [],\n  )\n","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/transloadit/uppy/blob/5d4dedd02a1ac0ae022c75c54aca76558f88e256/packages/@uppy/core/src/companion-client/googlePicker.ts#L406-L442","documentation":"Thrown while resolving the photos a user picked: a paginated GET of photospicker.googleapis.com/v1/mediaItems returned a non-OK response. It aborts resolution of the picked media items after the user has already made their selection in the Google Photos picker.","triggerScenarios":"During pollPickingSession -> resolvePickedPhotos, any mediaItems page fetch failing (expired token mid-pagination, 429 quota, 5xx) throws this error.","commonSituations":"Large selections requiring many pages hit rate limits; long picker sessions let the access token expire before all pages are fetched; transient Google Photos Picker errors.","solutions":["Retry the pick flow with a smaller selection","Provide an onAccessTokenRequired handler that silently refreshes the token so pagination never uses a stale token","Retry once after a short delay for transient failures","Check quota in Google Cloud Console if 429s recur"],"exampleFix":"// before\nconst picker = uppy.getPlugin('GooglePicker')\nawait picker.showPicker() // large selection -> Failed to get a media items\n\n// after\nrenderButton(uppy, {\n  clientId: 'xxx',\n  onAccessTokenRequired: async (pickerInstance) => {\n    const token = await getFreshToken() // silent re-auth\n    pickerInstance.setOAuthToken(token)\n  },\n})","handlingStrategy":"retry","validationCode":"null","typeGuard":"function isMediaItemsError(e: unknown): boolean {\n  return e instanceof Error && e.message === 'Failed to get a media items'\n}","tryCatchPattern":"try { await picker.showPicker() }\ncatch (err) {\n  if (isMediaItemsError(err)) {\n    uppy.info('Could not load all picked photos. Please pick fewer items and retry.', 'error', 5000)\n  }\n}","preventionTips":["Implement onAccessTokenRequired to silently refresh tokens mid-pagination","Suggest smaller selections in UI copy","Retry transient failures once before surfacing to the user"],"tags":["google-picker","google-photos","pagination","media-items"],"backgroundTag":"google-api-pagination-failed","analyzedSha":"5d4dedd02a1ac0ae022c75c54aca76558f88e256","analyzedAt":"2026-08-28T12:18:41.267Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}