immich-app/immich · error · BadRequestException
SyncRequestType.AssetFacesV1 is deprecated, use…
Error message
SyncRequestType.AssetFacesV1 is deprecated, use SyncRequestType.AssetFacesV2 instead
What it means
Generic deprecation guard: the AssetFacesV1 sync handler is now a stub that throws for any client still requesting SyncRequestType.AssetFacesV1, since face data moved to the AssetFacesV2 protocol. It always throws when the legacy type is selected, telling outdated clients to upgrade their sync request type; the at-fault input is the deprecated SyncRequestType.AssetFacesV1 query parameter.
Solutions
- Update the Immich mobile app to an AssetFacesV2-capable version
- Replace AssetFacesV1 with SyncRequestType.AssetFacesV2 in the sync request
Example fix
// before
requests: [{ type: SyncRequestType.AssetFacesV1 }]
// after
requests: [{ type: SyncRequestType.AssetFacesV2 }] Defensive patterns
Strategy: validation
Validate before calling
if (requests.some(r => r.type === SyncRequestType.AssetFacesV1)) throw new Error('Use AssetFacesV2'); Type guard
null
Try / catch
try {
await syncStream(requests);
} catch (e) {
if (e.status === 400 && e.message.includes('AssetFacesV1')) {
requests = requests.map(r => r.type === 'AssetFacesV1' ? { ...r, type: 'AssetFacesV2' } : r);
}
} Prevention
- Use AssetFacesV2 for face sync
- Keep the mobile app current
- Handle face deletes via AssetFaceDeleteV1 checkpoints
When it happens
Trigger: Client includes SyncRequestType.AssetFacesV1 in its sync request; handlers dispatches to syncAssetFacesV1 which always throws.
Common situations: Facial-recognition sync from older apps against a newer server.
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
- SyncRequestType.AlbumAssetsV1 is deprecated, use…
- SyncRequestType.AssetsV1 is deprecated, use…
- SyncRequestType.PartnerAssetsV1 is deprecated, use…
- Invalid ack type
- kUnsupportedOSError
AI-assisted analysis of immich-app/immich@f48d4b3321 (2026-09-15).
Data as JSON: /api/errors/a94c6744aa82f3e4.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/sync.service.ts:896
}
}
private async syncPeopleV1(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) {
const deleteType = SyncEntityType.PersonDeleteV1;
const deletes = this.syncRepository.person.getDeletes({ ...options, ack: checkpointMap[deleteType] });
for await (const { id, ...data } of deletes) {
await send(response, { type: deleteType, ids: [id], data });
}
const upsertType = SyncEntityType.PersonV1;
const upserts = this.syncRepository.person.getUpserts({ ...options, ack: checkpointMap[upsertType] });
for await (const { updateId, ...data } of upserts) {
await send(response, { type: upsertType, ids: [updateId], data });
}
}
private syncAssetFacesV1(): Promise<void> {
throw new BadRequestException(
'SyncRequestType.AssetFacesV1 is deprecated, use SyncRequestType.AssetFacesV2 instead',
);
}
// TODO(v5) drop when AssetFacesV2 is removed
private async syncAssetFacesV2(options: SyncQueryOptions, response: Writable, checkpointMap: CheckpointMap) {
const deleteType = SyncEntityType.AssetFaceDeleteV1;
const deletes = this.syncRepository.assetFace.getDeletesV2({ ...options, ack: checkpointMap[deleteType] });
for await (const { id, ...data } of deletes) {
await send(response, { type: deleteType, ids: [id], data });
}
const upsertType = SyncEntityType.AssetFaceV2;
const upserts = this.syncRepository.assetFace.getUpsertsV2({ ...options, ack: checkpointMap[upsertType] });
for await (const { updateId, ...data } of upserts) {
await send(response, { type: upsertType, ids: [updateId], data });
}
}View on GitHub (pinned to f48d4b3321)