{"record":{"id":"955cf7765d772a70","repo":"immich-app/immich","slug":"partner-already-exists","errorCode":null,"errorMessage":"Partner already exists","messagePattern":"Partner already exists","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"server/src/services/partner.service.ts","lineNumber":16,"sourceCode":"import { BadRequestException, Injectable } from '@nestjs/common';\nimport { Partner } from 'src/database.js';\nimport { AuthDto } from 'src/dtos/auth.dto.js';\nimport { PartnerCreateDto, PartnerResponseDto, PartnerSearchDto, PartnerUpdateDto } from 'src/dtos/partner.dto.js';\nimport { mapUser } from 'src/dtos/user.dto.js';\nimport { Permission } from 'src/enum.js';\nimport { PartnerDirection, PartnerIds } from 'src/repositories/partner.repository.js';\nimport { BaseService } from 'src/services/base.service.js';\n\n@Injectable()\nexport class PartnerService extends BaseService {\n  async create(auth: AuthDto, { sharedWithId }: PartnerCreateDto): Promise<PartnerResponseDto> {\n    const partnerId: PartnerIds = { sharedById: auth.user.id, sharedWithId };\n    const exists = await this.partnerRepository.get(partnerId);\n    if (exists) {\n      throw new BadRequestException(`Partner already exists`);\n    }\n\n    const user = await this.userRepository.get(sharedWithId, {});\n    if (!user) {\n      this.logger.debug('Partner creation failed: user not found');\n      throw new BadRequestException('Invalid user');\n    }\n\n    const partner = await this.partnerRepository.create(partnerId);\n    return this.mapPartner(partner, PartnerDirection.SharedBy);\n  }\n\n  async remove(auth: AuthDto, sharedWithId: string): Promise<void> {\n    const partnerId: PartnerIds = { sharedById: auth.user.id, sharedWithId };\n    const partner = await this.partnerRepository.get(partnerId);\n    if (!partner) {\n      throw new BadRequestException('Partner not found');\n    }","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/partner.service.ts#L1-L34","documentation":"PartnerService.create rejects the request when a partner record for the exact pair (sharedById=caller, sharedWithId=target user) already exists, since the partner relation is unique per ordered pair. It throws BadRequestException before creating a duplicate row.","triggerScenarios":"POST /api/partners with a sharedWithId for which the calling user already has an existing partner record (either direction previously created).","commonSituations":"Double-clicking the share button in the UI, replaying an API request, sharing with the same user from two clients, or retrying after a timeout where the first request actually succeeded.","solutions":["Check existing partners (GET /api/partners) before creating; treat an existing record as success.","Use a different target user if a different share was intended.","Delete the existing partner record (DELETE /api/partners/{id}) if it should be recreated.","Wrap creation client-side to handle 400 'Partner already exists' as an idempotent no-op."],"exampleFix":"// before\nawait api.partnersApi.createPartner({ sharedWithId: userId }); // throws if duplicate\n// after\nconst existing = await api.partnersApi.getPartners({ direction: 'shared-by' });\nif (!existing.some((p) => p.userId === userId)) {\n  await api.partnersApi.createPartner({ sharedWithId: userId });\n}","handlingStrategy":"validation","validationCode":"const existing = await api.partnersApi.getPartners({ direction: 'shared-by' });\nconst alreadyPartner = existing.some((p) => p.userId === sharedWithId);\nif (alreadyPartner) return; // idempotent no-op","typeGuard":null,"tryCatchPattern":"try {\n  await api.partnersApi.createPartner({ sharedWithId });\n} catch (e) {\n  if (e.status === 400 && String(e.message).includes('Partner already exists')) return; // treat as success\n  throw e;\n}","preventionTips":["Debounce/disable the share button while a request is in flight.","Check the partner list before offering share options.","Treat create as idempotent in clients."],"tags":["duplicate","partner","bad-request","idempotency"],"backgroundTag":"file-already-exists","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}