immich-app/immich · warning · BadRequestException
Can't delete a missing profile Image
Error message
Can't delete a missing profile Image
What it means
deleteProfileImage is called when the authenticated user has no profile image set (profileImagePath is the empty string). Deleting a nonexistent profile image is treated as a client error, so a 400 Bad Request is thrown before any update or file-delete job runs.
Solutions
- Check the user's profileImagePath (GET /users/me) before calling delete; skip the call when it is empty.
- Treat the 400 with this message as an idempotent no-op in the client rather than surfacing it as an error.
- If the UI shows a photo but the server says none exists, refresh user state — the image was already deleted elsewhere.
- Guard delete buttons in the UI to be disabled when no profile photo is set.
Example fix
// before
await api.deleteProfileImage();
// after
const me = await api.getMyUser();
if (me.profileImagePath) {
await api.deleteProfileImage();
} Defensive patterns
Strategy: validation
Validate before calling
const me = await api.getMyUser();
if (!me.profileImagePath) {
return; // nothing to delete
}
await api.deleteProfileImage(); Try / catch
try {
await api.deleteProfileImage();
} catch (e) {
if (e instanceof BadRequestException && e.message.includes('missing profile Image')) {
return; // already deleted — treat as no-op
}
throw e;
} Prevention
- Check profileImagePath before deleting.
- Treat delete-as-missing as idempotent success in clients.
- Refresh user state after any profile change to avoid stale UI.
- Debounce delete buttons to prevent duplicate calls.
When it happens
Trigger: DELETE /users/profile-image for a user whose profileImagePath === '' — i.e. the account never uploaded a profile photo, or it was already deleted (possibly by a concurrent request or the same client retrying).
Common situations: Client UI double-clicking the delete button; a stale client state showing a profile photo that was already removed in another tab/session; fresh accounts that never set a photo; scripts looping deletion over users.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Partner already exists
- Unable to process profile image
- Asset does not have valid dimensions
- Asset not found
- Asset not in stack
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/3b8fcd94145c8657.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/user.service.ts:139
const user = await this.userRepository.update(auth.user.id, {
profileImagePath,
profileChangedAt: new Date(),
});
const toDelete = [file.path, ...(oldPath ? [oldPath] : [])];
await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: toDelete } });
return {
userId: user.id,
profileImagePath: user.profileImagePath,
profileChangedAt: user.profileChangedAt,
};
}
async deleteProfileImage(auth: AuthDto): Promise<void> {
const user = await this.findOrFail(auth.user.id, { withDeleted: false });
if (user.profileImagePath === '') {
throw new BadRequestException("Can't delete a missing profile Image");
}
await this.userRepository.update(auth.user.id, { profileImagePath: '', profileChangedAt: new Date() });
await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [user.profileImagePath] } });
}
async getProfileImage(id: string): Promise<ImmichFileResponse> {
const user = await this.userRepository.get(id, {});
if (!user || !user.profileImagePath) {
this.logger.debug('User or profile image not found');
throw new NotFoundException();
}
return new ImmichFileResponse({
path: user.profileImagePath,
contentType: mimeTypes.lookup(user.profileImagePath),
cacheControl: CacheControl.None,
});
}View on GitHub (pinned to e55ac299a4)