{"record":{"id":"9e962a70830a304d","repo":"transloadit/uppy","slug":"unexpected-unsplash-response-missing-download-lin","errorCode":null,"errorMessage":"Unexpected Unsplash response: missing download links","messagePattern":"Unexpected Unsplash response: missing download links","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@uppy/companion/src/server/provider/unsplash/index.ts","lineNumber":77,"sourceCode":"\n  override async download({\n    id,\n    providerUserSession: { accessToken: token },\n  }: {\n    id: string\n    providerUserSession: UnsplashUserSession\n  }): Promise<{ stream: Readable; size: number | undefined }> {\n    return this.#withErrorHandling(\n      'provider.unsplash.download.error',\n      async () => {\n        const client = getClient({ token })\n\n        const {\n          links: { download: url, download_location: attributionUrl },\n        } = await getPhotoMeta(client, id)\n\n        if (!url || !attributionUrl) {\n          throw new Error(\n            'Unexpected Unsplash response: missing download links',\n          )\n        }\n\n        const stream = got.stream.get(url, { responseType: 'json' })\n        const { size } = await prepareStream(stream)\n\n        // To attribute the author of the image, we call the `download_location`\n        // endpoint to increment the download count on Unsplash.\n        // https://help.unsplash.com/en/articles/2511258-guideline-triggering-a-download\n        await client.get(attributionUrl, {\n          prefixUrl: '',\n          responseType: 'json',\n        })\n\n        // finally, stream on!\n        return { stream, size }\n      },","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/transloadit/uppy/blob/5d4dedd02a1ac0ae022c75c54aca76558f88e256/packages/@uppy/companion/src/server/provider/unsplash/index.ts#L59-L95","documentation":"Unsplash's download() fetches photo metadata and destructures links.download and links.download_location. If either is falsy in the API response, Companion throws 'Unexpected Unsplash Unsplash response: missing download links' because it can neither stream the file nor record attribution (required by the Unsplash API guidelines).","triggerScenarios":"Calling download() for a photo id whose Unsplash metadata lacks links.download or links.download_location — removed/deleted photos, an id from a different endpoint shape, or an Unsplash API change; also triggered by rate limiting responses that surface as malformed payloads.","commonSituations":"Stale photo ids cached client-side after the photo was deleted from Unsplash; Unsplash API contract changes; heavy usage hitting Unsplash rate limits and getting error bodies.","solutions":["Verify the photo id still exists via the Unsplash API before downloading","Handle this as a non-retryable error: remove the stale item and prompt the user to re-pick it","Check Unsplash API status/rate-limit headers if it affects many photos","Keep the Unsplash application credentials healthy so metadata requests succeed"],"exampleFix":"// before\nconst { stream } = await provider.download({ id, providerUserSession })\n\n// after\nlet stream\ntry {\n  ({ stream } = await provider.download({ id, providerUserSession }))\n} catch (err) {\n  if (err.message.includes('missing download links')) {\n    uppy.removeFile(fileId) // stale/removed photo\n    return\n  }\n  throw err\n}","handlingStrategy":"fallback","validationCode":"// verify the photo still exists before download\nconst meta = await fetch(`https://api.unsplash.com/photos/${id}`, { headers: { Authorization: `Client-ID ${key}` } })\nif (!meta.ok) { /* stale id: remove item, skip download */ }","typeGuard":null,"tryCatchPattern":"try { await provider.download(args) } catch (e) { if (e instanceof Error && e.message.includes('missing download links')) { uppy.removeFile(fileId); return null } throw e }","preventionTips":["Treat cached Unsplash ids as potentially stale; re-validate before download","Handle per-file failures gracefully instead of failing the whole batch"],"tags":["unsplash","download","api-contract","attribution","companion"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"5d4dedd02a1ac0ae022c75c54aca76558f88e256","analyzedAt":"2026-08-28T12:18:41.267Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}