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

  1. Verify the server URL is reachable (curl -v <url>) from the client's network
  2. Start the Immich server / check container health and port mappings
  3. Check reverse proxy, TLS certificate, and firewall rules for the host
  4. 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

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


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)