immich-app/immich · error · ApiException
Server is not reachable
Error message
Server is not reachable
What it means
The API service resolves the server URL and probes it with _isEndpointAvailable; if the endpoint does not respond, it throws an ApiException with HTTP status 503 meaning the server cannot be reached. It is used during server-URL validation/normalization (e.g. login flow).
Solutions
- Verify the server URL is reachable (curl -v <url>) from the client's network
- Start the Immich server / check container health and port mappings
- Check reverse proxy, TLS certificate, and firewall rules for the host
- Show a retry/network-status message in the UI instead of proceeding
Example fix
// before final url = 'https://immich.example.com:2283/app'; // typo path // after final url = 'https://immich.example.com:2283'; // correct base URL, verified reachable
Defensive patterns
Strategy: retry
Validate before calling
final uri = Uri.tryParse(rawUrl);
if (uri == null || !uri.hasScheme || !uri.host.isNotEmpty) throw FormatException('bad url');
final ok = await http.head(uri.replace(path: '/api/server/ping')).timeout(5s); Type guard
bool isValidServerUrl(String url) => Uri.tryParse(url) != null && Uri.parse(url).hasScheme;
Try / catch
try {
final endpoint = await api.resolveServerUrl(url);
} on ApiException catch (e) {
if (e.status == 503) promptRetryWithNetworkStatus();
else rethrow;
} Prevention
- Validate URL format before calling resolution
- Ping the server with a short timeout before login
- Show connectivity status and offer retry in the UI
- Document correct server URL format (no /api suffix) to users
When it happens
Trigger: Calling the server URL resolution routine where _getWellKnownEndpoint succeeds (or is empty) but _isEndpointAvailable(url) returns false — connection refused, DNS failure, TLS error, or non-reachable host on the resolved URL.
Common situations: User typos the server URL in the login screen; self-hosted Immich server is stopped or behind a misconfigured reverse proxy; firewall/VPN blocks the port; well-known endpoint redirects to an unreachable address.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- await response.text()
- EOFException
- errors.unable_to_upload_file
- Failed to fetch activation key
- Machine learning request to
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/8404299a9360ae1f.
Report an issue: GitHub.
Appendix: source
Thrown at mobile/lib/services/api.service.dart:104
/// Takes a server URL and attempts to resolve the API endpoint.
///
/// Input: [schema://]host[:port][/path]
/// schema - optional (default: https)
/// host - required
/// port - optional (default: based on schema)
/// path - optional
Future<String> resolveEndpoint(String serverUrl) async {
String url = normalizeServerUrl(serverUrl);
// Check for /.well-known/immich
final wellKnownEndpoint = await _getWellKnownEndpoint(url);
if (wellKnownEndpoint.isNotEmpty) {
url = normalizeServerUrl(wellKnownEndpoint);
}
if (!await _isEndpointAvailable(url)) {
throw ApiException(503, "Server is not reachable");
}
// Otherwise, assume the URL provided is the api endpoint
return url;
}
Future<bool> _isEndpointAvailable(String serverUrl) async {
final endpoint = serverUrl.endsWith('/api') ? serverUrl : '$serverUrl/api';
try {
setEndpoint(endpoint);
await serverInfoApi.pingServer().timeout(const Duration(seconds: 5));
} on TimeoutException catch (_) {
return false;
} on SocketException catch (_) {
return false;
} catch (error, stackTrace) {
_log.severe("Error while checking server availability", error, stackTrace);View on GitHub (pinned to e55ac299a4)