{"record":{"id":"3b8fcd94145c8657","repo":"immich-app/immich","slug":"can-t-delete-a-missing-profile-image","errorCode":null,"errorMessage":"Can't delete a missing profile Image","messagePattern":"Can't delete a missing profile Image","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"server/src/services/user.service.ts","lineNumber":139,"sourceCode":"    const user = await this.userRepository.update(auth.user.id, {\n      profileImagePath,\n      profileChangedAt: new Date(),\n    });\n\n    const toDelete = [file.path, ...(oldPath ? [oldPath] : [])];\n    await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: toDelete } });\n\n    return {\n      userId: user.id,\n      profileImagePath: user.profileImagePath,\n      profileChangedAt: user.profileChangedAt,\n    };\n  }\n\n  async deleteProfileImage(auth: AuthDto): Promise<void> {\n    const user = await this.findOrFail(auth.user.id, { withDeleted: false });\n    if (user.profileImagePath === '') {\n      throw new BadRequestException(\"Can't delete a missing profile Image\");\n    }\n    await this.userRepository.update(auth.user.id, { profileImagePath: '', profileChangedAt: new Date() });\n    await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [user.profileImagePath] } });\n  }\n\n  async getProfileImage(id: string): Promise<ImmichFileResponse> {\n    const user = await this.userRepository.get(id, {});\n    if (!user || !user.profileImagePath) {\n      this.logger.debug('User or profile image not found');\n      throw new NotFoundException();\n    }\n\n    return new ImmichFileResponse({\n      path: user.profileImagePath,\n      contentType: mimeTypes.lookup(user.profileImagePath),\n      cacheControl: CacheControl.None,\n    });\n  }","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/user.service.ts#L121-L157","documentation":"A BadRequestException (HTTP 400) thrown by UserService.deleteProfileImage when the user's profileImagePath is already an empty string, meaning there is no profile image to remove. The guard prevents a pointless FileDelete job and signals the client that the state is already as requested.","triggerScenarios":"DELETE /users/profile-image called by a user who never set a profile image, or who already deleted it. The check is a strict equality against the empty string.","commonSituations":"UI shows a default avatar but still offers a delete action; a retry of a delete that already succeeded; double-click on the remove button before the UI updates.","solutions":["Disable the 'remove profile image' control in the UI when the user has no custom image.","Treat the 400 as success idempotently on the client since the desired state (no image) already holds.","Before calling, GET the user profile and only send the delete if profileImagePath is non-empty."],"exampleFix":"// before\nawait api.deleteProfileImage(); // 400 when already empty\n\n// after\nconst me = await api.getUserMe();\nif (me.profileImagePath) {\n  await api.deleteProfileImage();\n}","handlingStrategy":"validation","validationCode":"const me = await api.getUserMe();\nif (!me.profileImagePath) {\n  return { ok: true, skipped: true, reason: 'No profile image to delete' };\n}","typeGuard":"const isMissingProfileImageError = (e: unknown): boolean =>\n  typeof e === 'object' && e !== null && (e as any).status === 400 && (e as any).message === \"Can't delete a missing profile Image\";","tryCatchPattern":"try {\n  await api.deleteProfileImage();\n} catch (e) {\n  if (isMissingProfileImageError(e)) {\n    // already in desired state; treat as success\n    return;\n  }\n  throw e;\n}","preventionTips":["Disable the remove-profile-image control when profileImagePath is empty.","Treat this 400 as idempotent success on the client.","Guard against double-submit on the remove button."],"tags":["profile-image","idempotency","validation","nestjs"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}