immich-app/immich · error · BadRequestException
Invalid user
Error message
Invalid user
What it means
On album creation, any albumUsers entries other than the owner are checked against the user repository; if a listed userId does not exist, creation is aborted with 'Invalid user'. This prevents creating albums that reference dangling user IDs.
Solutions
- Remove the nonexistent userId from albumUsers and retry
- Refresh the shareable-user list from the API before creating the album
- Verify the userId is a valid UUID belonging to this instance
- Handle the 400 at the client and re-prompt the user to select share targets
Example fix
// before
const valid = await Promise.all(ids.map(id => userRepository.get(id, {})));
await api.createAlbum({ albumUsers: ids.map(id => ({ userId: id })) });
// after
const existing = (await api.listUsers()).users.map(u => u.id);
await api.createAlbum({ albumUsers: ids.filter(id => existing.includes(id)).map(id => ({ userId: id })) }); Defensive patterns
Strategy: validation
Validate before calling
const validIds = new Set((await api.listUsers()).map(u => u.id)); const albumUsers = requested.filter(u => validIds.has(u.userId));
Type guard
function userExists(id: string, known: Set<string>): boolean {
return known.has(id);
} Try / catch
try {
await api.createAlbum(dto);
} catch (e) {
if ((e as Error).message === 'Invalid user') {
await refreshUserCache();
return retryWithoutInvalidUsers(dto);
}
throw e;
} Prevention
- Refresh the shareable-users list before creating albums
- Exclude the owner's own id from albumUsers (service filters it anyway)
- Validate UUIDs client-side before submission
- Handle user deletion events by pruning cached share lists
When it happens
Trigger: POST /albums with dto.albumUsers containing a userId that is not an existing user (typo, deleted user, or user from another instance).
Common situations: Stale client caches listing removed users, copy-pasted UUIDs from another environment, or concurrent user deletion between listing and album creation.
Understand the failure class
Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.
Related errors
- Album not shared with user
- Cannot add another owner
- Invalid album thumbnail
- Invalid albumId
- User not found
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/9d61aca4f1842906.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/album.service.ts:108
async getMapMarkers(auth: AuthDto, id: string): Promise<MapMarkerResponseDto[]> {
await this.requireAccess({ auth, permission: Permission.AlbumRead, ids: [id] });
if (auth.sharedLink && !auth.sharedLink.showExif) {
return [];
}
return this.mapRepository.getAlbumMapMarkers(id);
}
async create(auth: AuthDto, dto: CreateAlbumDto): Promise<AlbumResponseDto> {
const albumUsers = (dto.albumUsers || []).filter(({ userId }) => userId !== auth.user.id);
for (const { userId } of albumUsers) {
const exists = await this.userRepository.get(userId, {});
if (!exists) {
this.logger.debug('Album creation failed: user not found');
throw new BadRequestException('Invalid user');
}
}
const allowedAssetIdsSet = await this.checkAccess({
auth,
permission: Permission.AssetShare,
ids: dto.assetIds || [],
});
const assetIds = [...allowedAssetIdsSet].map((id) => id);
const userMetadata = await this.userRepository.getMetadata(auth.user.id);
const album = await this.albumRepository.create(
{
albumName: dto.albumName,
description: dto.description,
albumThumbnailAssetId: assetIds[0] || null,
order: getPreferences(userMetadata).albums.defaultAssetOrder,View on GitHub (pinned to e55ac299a4)