immich-app/immich · error · BadRequestException
Asset not found
Error message
Asset not found
What it means
Thrown by AssetService.getOne when assetRepository.getById returns null after requireAccess already confirmed the user has AssetRead permission. Because the access check passed, the most likely cause is a race: the asset was deleted between the access check and the detail fetch. Returned as BadRequestException (HTTP 400), not 404.
Source
Thrown at server/src/services/asset.service.ts:75
const stats = await this.assetRepository.getStatistics(auth.user.id, dto);
return mapStats(stats);
}
async get(auth: AuthDto, id: string): Promise<AssetResponseDto | SanitizedAssetResponseDto> {
await this.requireAccess({ auth, permission: Permission.AssetRead, ids: [id] });
const asset = await this.assetRepository.getById(id, {
exifInfo: true,
owner: true,
faces: { person: true },
stack: { assets: true },
edits: true,
tags: true,
});
if (!asset) {
throw new BadRequestException('Asset not found');
}
if (auth.sharedLink && !auth.sharedLink.showExif) {
return mapAsset(asset, { stripMetadata: true, withStack: true, auth });
}
const data = mapAsset(asset, { withStack: true, auth });
if (auth.sharedLink) {
delete data.owner;
}
if (data.ownerId !== auth.user.id || auth.sharedLink) {
data.people = [];
}
return data;
}View on GitHub (pinned to 199723261c)
Solutions
- Refresh the asset list after any delete to remove stale ids
- Treat 400 'Asset not found' as removal and drop the asset from local state
- Avoid concurrent delete+view of the same asset
Defensive patterns
Strategy: try-catch
Try / catch
try {
return await sdk.getAsset(id);
} catch (e) {
if (e instanceof HttpError && e.status === 400 && /Asset not found/.test(e.message)) {
ui.removeAsset(id); // stale reference, drop it
return null;
}
throw e;
} Prevention
- Refresh the asset list after any delete to remove stale ids
- Treat 'Asset not found' as removal from local state
- Avoid concurrent delete + detail view of the same asset
When it happens
Trigger: GET /assets/:id that passes access control but finds no row on the detailed getById (with exifInfo, owner, faces, stack, edits, tags relations). Concurrent delete is the classic trigger.
Common situations: Timeline still showing an asset after it was deleted from another client; long-lived detail view while a cleanup job runs; optimistic UI not refreshing after delete.
Related errors
- API Key not found
- Asset media not found
- Asset not found or asset is not a video
- Both assets must exist
- Asset not found
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/26a53c6a6ae7e951.
Report an issue: GitHub.