{"record":{"id":"c9fa760bc80124d1","repo":"immich-app/immich","slug":"assetids-albumid-or-userid-is-required","errorCode":null,"errorMessage":"assetIds, albumId, or userId is required","messagePattern":"assetIds, albumId, or userId is required","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/download.service.ts","lineNumber":36,"sourceCode":"@Injectable()\nexport class DownloadService extends BaseService {\n  async getDownloadInfo(auth: AuthDto, dto: DownloadInfoDto): Promise<DownloadResponseDto> {\n    let assets;\n\n    if (dto.assetIds) {\n      const assetIds = dto.assetIds;\n      await this.requireAccess({ auth, permission: Permission.AssetDownload, ids: assetIds });\n      assets = this.downloadRepository.downloadAssetIds(assetIds);\n    } else if (dto.albumId) {\n      const albumId = dto.albumId;\n      await this.requireAccess({ auth, permission: Permission.AlbumDownload, ids: [albumId] });\n      assets = this.downloadRepository.downloadAlbumId(albumId);\n    } else if (dto.userId) {\n      const userId = dto.userId;\n      await this.requireAccess({ auth, permission: Permission.TimelineDownload, ids: [userId] });\n      assets = this.downloadRepository.downloadUserId(userId);\n    } else {\n      throw new BadRequestException('assetIds, albumId, or userId is required');\n    }\n\n    const targetSize = dto.archiveSize || HumanReadableSize.GiB * 4;\n    const metadata = await this.userRepository.getMetadata(auth.user.id);\n    const preferences = getPreferences(metadata);\n    const motionIds = new Set<string>();\n    const archives: DownloadArchiveInfo[] = [];\n    let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };\n\n    const addToArchive = ({ id, size }: { id: string; size: number | null }) => {\n      archive.assetIds.push(id);\n      archive.size += Number(size || 0);\n\n      if (archive.size > targetSize) {\n        archives.push(archive);\n        archive = { size: 0, assetIds: [] };\n      }\n    };","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/download.service.ts#L18-L54","documentation":"getDownloadInfo requires exactly one of assetIds, albumId, or userId in the DTO to determine which assets to include in the download archive. When none is provided, no asset source can be selected and a 400 BadRequestException is thrown.","triggerScenarios":"POST /download/info with an empty body or a DTO missing all three identifiers — e.g. calling the API directly without a body, or a client UI bug clearing the selection before requesting the archive.","commonSituations":"Manual API/curl calls omitting the payload; frontend sending only filters like albumName not supported by the DTO; empty multi-select download attempts.","solutions":["Include exactly one of assetIds (array), albumId, or userId in the request body.","If downloading an album, send {\"albumId\":\"<uuid>\"}; for selected assets send assetIds; for a user's library send userId.","Fix the client to disable the download action until a selection/album is chosen."],"exampleFix":"// before\nawait api.post('/download/info', {});\n// after\nawait api.post('/download/info', { albumId: album.id });","handlingStrategy":"validation","validationCode":"const sources = ['assetIds', 'albumId', 'userId'].filter((k) => dto[k] != null && (k !== 'assetIds' || dto[k].length));\nif (sources.length !== 1) throw new Error('Download info requires exactly one of assetIds, albumId, or userId');","typeGuard":null,"tryCatchPattern":"try {\n  await api.post('/download/info', dto);\n} catch (e) {\n  if (e.status === 400 && /assetIds, albumId, or userId/.test(e.message)) {\n    console.error('Add a selection to the download request body');\n  } else throw e;\n}","preventionTips":["Disable the download button until the user selects assets or an album.","Type the request DTO so exactly one identifier field is set.","Add a client-side precondition check before calling /download/info."],"tags":["bad-request","validation","download"],"backgroundTag":"missing-required-argument","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}