immich-app/immich · error · BadRequestException
assetIds, albumId, or userId is required
Error message
assetIds, albumId, or userId is required
What it means
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.
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.
Example fix
// before
await api.post('/download/info', {});
// after
await api.post('/download/info', { albumId: album.id }); Defensive patterns
Strategy: validation
Validate before calling
const sources = ['assetIds', 'albumId', 'userId'].filter((k) => dto[k] != null && (k !== 'assetIds' || dto[k].length));
if (sources.length !== 1) throw new Error('Download info requires exactly one of assetIds, albumId, or userId'); Try / catch
try {
await api.post('/download/info', dto);
} catch (e) {
if (e.status === 400 && /assetIds, albumId, or userId/.test(e.message)) {
console.error('Add a selection to the download request body');
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Manual API/curl calls omitting the payload; frontend sending only filters like albumName not supported by the DTO; empty multi-select download attempts.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- At least two people are required for merging
- Cannot request to join your own cluster group
- error instanceof Error ? error.message : error
- {error.message}
- Invalid ack type
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/c9fa760bc80124d1.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/download.service.ts:36
@Injectable()
export class DownloadService extends BaseService {
async getDownloadInfo(auth: AuthDto, dto: DownloadInfoDto): Promise<DownloadResponseDto> {
let assets;
if (dto.assetIds) {
const assetIds = dto.assetIds;
await this.requireAccess({ auth, permission: Permission.AssetDownload, ids: assetIds });
assets = this.downloadRepository.downloadAssetIds(assetIds);
} else if (dto.albumId) {
const albumId = dto.albumId;
await this.requireAccess({ auth, permission: Permission.AlbumDownload, ids: [albumId] });
assets = this.downloadRepository.downloadAlbumId(albumId);
} else if (dto.userId) {
const userId = dto.userId;
await this.requireAccess({ auth, permission: Permission.TimelineDownload, ids: [userId] });
assets = this.downloadRepository.downloadUserId(userId);
} else {
throw new BadRequestException('assetIds, albumId, or userId is required');
}
const targetSize = dto.archiveSize || HumanReadableSize.GiB * 4;
const metadata = await this.userRepository.getMetadata(auth.user.id);
const preferences = getPreferences(metadata);
const motionIds = new Set<string>();
const archives: DownloadArchiveInfo[] = [];
let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };
const addToArchive = ({ id, size }: { id: string; size: number | null }) => {
archive.assetIds.push(id);
archive.size += Number(size || 0);
if (archive.size > targetSize) {
archives.push(archive);
archive = { size: 0, assetIds: [] };
}
};View on GitHub (pinned to e55ac299a4)