immich-app/immich · error · BadRequestException

SyncRequestType.PartnerAssetsV1 is deprecated, use…

Error message

SyncRequestType.PartnerAssetsV1 is deprecated, use SyncRequestType.PartnerAssetsV2 instead

What it means

Generic deprecation guard: syncPartnerAssetsV1 rejects sync requests that still ask for the old SyncRequestType.PartnerAssetsV1 protocol, directing clients to migrate to PartnerAssetsV2. It throws unconditionally whenever the legacy sync type is selected, acting as a hard cutover so old partner-asset sync sessions cannot continue; the at-fault input is the deprecated SyncRequestType.PartnerAssetsV1 query parameter.

Solutions

  1. Update the Immich mobile app to a PartnerAssetsV2-capable version
  2. Switch the client sync request to SyncRequestType.PartnerAssetsV2

Example fix

// before
requests: [{ type: SyncRequestType.PartnerAssetsV1 }]
// after
requests: [{ type: SyncRequestType.PartnerAssetsV2 }]
Defensive patterns

Strategy: validation

Validate before calling

if (requests.some(r => r.type === SyncRequestType.PartnerAssetsV1)) throw new Error('Use PartnerAssetsV2');

Type guard

null

Try / catch

try {
  await syncStream(requests);
} catch (e) {
  if (e.status === 400 && e.message.includes('PartnerAssetsV1')) {
    requests = requests.map(r => r.type === 'PartnerAssetsV1' ? { ...r, type: 'PartnerAssetsV2' } : r);
  }
}

Prevention

When it happens

Trigger: Client requests SyncRequestType.PartnerAssetsV1 in a sync query; handlers routes to syncPartnerAssetsV1 which always throws.

Common situations: Outdated mobile client after server upgrade; partner-sharing sync codepaths in older apps.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


AI-assisted analysis of immich-app/immich@f48d4b3321 (2026-09-15). Data as JSON: /api/errors/ec041ea04fb60e37. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/sync.service.ts:345

    throw new BadRequestException('SyncRequestType.AssetsV1 is deprecated, use SyncRequestType.AssetsV2 instead');
  }

  private async syncAssetsV2(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) {
    const deleteType = SyncEntityType.AssetDeleteV1;
    const deletes = this.syncRepository.asset.getDeletes({ ...options, ack: checkpointMap[deleteType] });
    for await (const { id, ...data } of deletes) {
      await send(response, { type: deleteType, ids: [id], data });
    }

    const upsertType = SyncEntityType.AssetV2;
    const upserts = this.syncRepository.asset.getUpserts({ ...options, ack: checkpointMap[upsertType] });
    for await (const { updateId, ...data } of upserts) {
      await send(response, { type: upsertType, ids: [updateId], data: mapSyncAssetV2(data) });
    }
  }

  private syncPartnerAssetsV1(): Promise<void> {
    throw new BadRequestException(
      'SyncRequestType.PartnerAssetsV1 is deprecated, use SyncRequestType.PartnerAssetsV2 instead',
    );
  }

  private async syncPartnerAssetsV2(
    options: SyncQueryOptions,
    response: Writable,
    checkpointMap: CheckpointMap,
    sessionId: string,
  ) {
    const deleteType = SyncEntityType.PartnerAssetDeleteV1;
    const deletes = this.syncRepository.partnerAsset.getDeletes({ ...options, ack: checkpointMap[deleteType] });
    for await (const { id, ...data } of deletes) {
      await send(response, { type: deleteType, ids: [id], data });
    }

    const backfillType = SyncEntityType.PartnerAssetBackfillV2;
    const backfillCheckpoint = checkpointMap[backfillType];

View on GitHub (pinned to f48d4b3321)