immich-app/immich · error · Exception

Cast session is not established

Error message

Cast session is not established

What it means

GcastRepository.sendMessage forwards a message to the connected Google Cast session. If no session has been established (connectToDestination not yet called or the session was lost), _castSession is null and the method throws 'Cast session is not established' rather than dereferencing null or silently dropping the message.

Solutions

  1. Check that a cast session exists before sending: expose a getter (e.g. isSessionEstablished) or track connection state and disable send controls when unconnected.
  2. Call the connect/establish-session method and await its completion before invoking sendMessage.
  3. Handle Cast session lifecycle events (suspended/ended) to reset UI state and force a reconnect on send failure.
  4. Wrap sendMessage in try-catch and on failure prompt the user to reconnect to the cast device.

Example fix

// before
gcastRepository.sendMessage(ns, payload);
// after
if (!gcastRepository.isSessionEstablished) {
  await gcastRepository.connectToDestination(deviceId);
}
gcastRepository.sendMessage(ns, payload);
Defensive patterns

Strategy: validation

Validate before calling

if (gcastRepository.isSessionEstablished) {
  gcastRepository.sendMessage(ns, payload);
} else {
  await reconnectAndSend(ns, payload);
}

Type guard

bool canSendMessage(GcastRepository repo) => repo.isSessionEstablished;

Try / catch

try {
  gcastRepository.sendMessage(ns, payload);
} catch (e) {
  if (e.toString().contains('Cast session is not established')) {
    await gcastRepository.connectToDestination(deviceId);
    gcastRepository.sendMessage(ns, payload);
  } else {
    rethrow;
  }
}

Prevention

When it happens

Trigger: Calling sendMessage(namespace, message) before a successful connect/establishCastSession, after the receiver disconnects (session closed/expired), or after app resume when the cached session was invalidated.

Common situations: User taps a cast action while the device picker/connection flow never completed; Cast device drops off the network mid-session; UI state still shows 'casting' after session teardown so buttons remain enabled.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/39965d89d5e79dde. Report an issue: GitHub.

Appendix: source

Thrown at mobile/lib/repositories/gcast.repository.dart:59

    sendMessage(CastSession.kNamespaceReceiver, {'type': "STOP", "sessionId": sessionID});

    // wait 500ms to ensure the stop command is processed
    await Future.delayed(const Duration(milliseconds: 500));

    await _castSession?.close();
  }

  String? getSessionId() {
    if (_receiverStatus == null) {
      return null;
    }
    return _receiverStatus!['status']['applications'][0]['sessionId'];
  }

  void sendMessage(String namespace, Map<String, dynamic> message) {
    if (_castSession == null) {
      throw Exception("Cast session is not established");
    }

    _castSession!.sendMessage(namespace, message);
  }

  Future<List<CastDevice>> listDestinations() async {
    return await CastDiscoveryService().search(timeout: const Duration(seconds: 3));
  }
}

View on GitHub (pinned to e55ac299a4)