immich-app/immich · error · BadRequestException
Invalid ack type: ${type}
Error message
Invalid ack type: ${type} What it means
Thrown (as BadRequestException) in SyncService.setAcks when an ack decoded by fromAck(ack) yields a type that is not a member of the SyncEntityType enum. It is a placeholder guard (the TODO notes class-validator validation is planned) that rejects unknown ack types before they reach the checkpoint upsert.
Source
Thrown at server/src/services/sync.service.ts:113
return this.syncCheckpointRepository.getAll(sessionId);
}
async setAcks(auth: AuthDto, dto: SyncAckSetDto) {
const sessionId = auth.session?.id;
if (!sessionId) {
return throwSessionRequired();
}
const checkpoints: Record<string, Insertable<SessionSyncCheckpointTable>> = {};
for (const ack of dto.acks) {
const { type } = fromAck(ack);
if (type === SyncEntityType.SyncResetV1) {
await this.sessionRepository.resetSyncProgress(sessionId);
return;
}
// TODO proper ack validation via class validator
if (!Object.values(SyncEntityType).includes(type)) {
throw new BadRequestException(`Invalid ack type: ${type}`);
}
// TODO pick the latest ack for each type, instead of using the last one
checkpoints[type] = { sessionId, type, ack };
}
await this.syncCheckpointRepository.upsertAll(Object.values(checkpoints));
}
async deleteAcks(auth: AuthDto, dto: SyncAckDeleteDto) {
const sessionId = auth.session?.id;
if (!sessionId) {
return throwSessionRequired();
}
await this.syncCheckpointRepository.deleteAll(sessionId, dto.types);
}
View on GitHub (pinned to 199723261c)
Solutions
- Upgrade the client to match the server's SyncEntityType values; re-fetch the openapi schema.
- Drop unknown ack types on the client before submitting (filter against the documented enum).
- Pin client and server to the same Immich version until ack types stabilize.
- Inspect the request body; the failing type is echoed back in the message.
Example fix
// before
await api.syncAcks([{ type: 'AssetV1', ack: '...' }]);
// after
await api.syncAcks([{ type: 'AssetV2', ack: '...' }]); Defensive patterns
Strategy: validation
Validate before calling
import { SyncEntityType } from './openapi';
const validTypes = new Set(Object.values(SyncEntityType));
const safeAcks = dto.acks.filter(a => validTypes.has(fromAck(a).type));
await syncApi.setAcks({ acks: safeAcks }); Type guard
function isKnownSyncEntityType(t: unknown): t is SyncEntityType {
return typeof t === 'string' && Object.values(SyncEntityType).includes(t as SyncEntityType);
} Try / catch
try { await syncApi.setAcks({ acks }); }
catch (e) {
if (e instanceof BadRequestException && /Invalid ack type/.test(e.message)) {
// re-fetch enum, filter unknown acks, retry once
}
} Prevention
- Pin client and server Immich versions together.
- Regenerate the SDK from the deployed openapi after each server upgrade.
- Validate ack types client-side against the generated enum before submit.
When it happens
Trigger: POST /sync/acks with a body whose acks[].type string does not match any SyncEntityType value, e.g. an old client sending a renamed/removed entity type, or a hand-crafted payload.
Common situations: Client/server version skew (server upgraded, client still emits a v1 ack); typo in a custom integration; SDK regenerated against a newer enum than the deployed server.
Related errors
- SyncRequestType.AssetsV1 is deprecated, use SyncRequestType.
- SyncRequestType.PartnerAssetsV1 is deprecated, use SyncReque
- SyncRequestType.AlbumAssetsV1 is deprecated, use SyncRequest
- SyncRequestType.AssetFacesV1 is deprecated, use SyncRequestT
- assetIds, albumId, or userId is required
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/f8a3651b9c5fa476.
Report an issue: GitHub.