immich-app/immich · error · ApiException
Failed to get sync stream: $errorBody
Error message
Failed to get sync stream: $errorBody
What it means
The sync-stream repository opens an HTTP request and expects status 200. Any other status aborts the stream before reading: the error body is drained and wrapped in an ApiException carrying the status code and the raw response body under the message 'Failed to get sync stream: ...'.
Solutions
- Log the included status code and error body to identify the server-side cause
- Refresh authentication (re-login / token renewal) on 401/403 before retrying
- Retry with backoff on 5xx / transient gateway errors
- Confirm the server version supports the sync-stream endpoint
Example fix
// before
final delta = await syncApi.getSyncStream(...); // throws raw ApiException
// after
try {
await syncApi.getSyncStream(...);
} on ApiException catch (e) {
if (e.code == 401) await reauthenticate();
else if (e.code >= 500) scheduleRetryWithBackoff();
rethrow;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Dart: sanity-check session before opening the stream
if (accessToken == null || serverUrl == null) {
throw StateError('Not authenticated for sync stream');
} Try / catch
try {
await for (final chunk in syncApi.getSyncStream(...)) { ... }
} on ApiException catch (e) {
if (e.code == 401 || e.code == 403) {
await reauthenticate();
} else if (e.code >= 500) {
retryWithBackoff();
}
} Prevention
- Refresh tokens proactively before long sync sessions
- Verify server version supports the sync-stream endpoint
- Check proxy/CDN timeouts for streaming responses
- Log status + body from ApiException for diagnosis
When it happens
Trigger: Server responds with non-200 (401 expired token, 403, 500, 502) to the sync-stream request; server endpoint missing or a proxy intercepts the stream request.
Common situations: Access token expired between login and sync; server upgraded/changed API so the sync endpoint errors; reverse proxy or CDN rejects long-lived streaming requests; server error while checkpointing.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- await response.text()
- EOFException
- errors.unable_to_upload_file
- Expected a JSON response
- Failed to fetch activation key
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/b3cffea2e716142f.
Report an issue: GitHub.
Appendix: source
Thrown at mobile/lib/infrastructure/repositories/sync_api.repository.dart:89
String previousChunk = '';
final List<String> lines = [];
bool shouldAbort = false;
void abort() {
_logger.warning("Abort requested, stopping sync stream");
shouldAbort = true;
}
final reset = onReset ?? () {};
try {
final response = await client.send(request);
if (response.statusCode != 200) {
final errorBody = await response.stream.bytesToString();
throw ApiException(response.statusCode, 'Failed to get sync stream: $errorBody');
}
await for (final chunk in response.stream.transform(utf8.decoder)) {
if (shouldAbort) {
break;
}
previousChunk += chunk;
final parts = previousChunk.split('\n');
previousChunk = parts.removeLast();
lines.addAll(parts);
if (lines.length < batchSize) {
continue;
}
await onData(_parseLines(lines), abort, reset);
lines.clear();View on GitHub (pinned to e55ac299a4)