tonhowtf/omniget · warning

[omnidisc] could not read cached plaintext

Error message

[omnidisc] could not read cached plaintext

What it means

hydrateEncrypted fetches cached decrypted message plaintext from the backend (a ciphertext→raw map) and applies each entry via applyDecrypted. If the backend read rejects or the map is unusable, the warning is logged and hydration silently fails — messages remain encrypted placeholders until a live `omnidisc://decrypted` event arrives.

Solutions

  1. Check errorText(e) to distinguish backend read failure from empty cache
  2. Verify the decryption keys for the channel exist/are loaded on this device
  3. Confirm the cached payload format matches readPayload's expectations (version skew)
  4. Fall back to live decryption: the hydrate path is optional since live decrypted events repopulate state
Defensive patterns

Strategy: fallback

Validate before calling

// skip hydration when there is nothing cached to read
if (!channelId || decryptedCount(channelId) > 0) return;

Type guard

function isPayloadMap(v: unknown): v is Record<string, unknown> {
  return typeof v === "object" && v !== null;
}

Try / catch

try {
  const found = await invoke<Record<string, unknown>>("omnidisc_cached_plaintext", { channelId });
  for (const [ct, raw] of Object.entries(found ?? {})) {
    const payload = readPayload(raw);
    if (payload) applyDecrypted(channelId, ct, payload);
  }
} catch (e) {
  console.warn("[omnidisc] could not read cached plaintext", errorText(e));
}

Prevention

When it happens

Trigger: Calling hydrateEncrypted(channelId) when the backend command returning the cached plaintext map rejects: key store/decryption service unavailable, no cache entry for the channel, serialization mismatch on the returned map, or encrypted payloads that fail readPayload parsing.

Common situations: First device login with an empty local decryption cache; corrupted or rotated encryption keys; backend restarted and cache lost; schema change in the cached payload format after an app update so readPayload returns null for every entry.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/b263b6035fa47131. Report an issue: GitHub.

Appendix: source

Thrown at src/lib/stores/omnidisc-store.svelte.ts:2480

/// local cache in Rust. Anything it cannot recall stays honestly blank.
export async function hydrateEncrypted(channelId: string) {
  const instance = instanceForChannel(channelId);
  if (!instance || isDemo(instance.id)) return;
  const waiting = (messagesByChannel[channelId] ?? [])
    .filter((m) => m.awaitingDecryption && m.ciphertext)
    .map((m) => m.ciphertext as string);
  if (waiting.length === 0) return;
  try {
    const found = await invoke<Record<string, unknown>>("omnidisc_mls_recall", {
      url: instance.url,
      ciphertexts: waiting,
    });
    for (const [ciphertext, raw] of Object.entries(found ?? {})) {
      const payload = readPayload(raw);
      if (payload) applyDecrypted(channelId, ciphertext, payload);
    }
  } catch (e) {
    console.warn("[omnidisc] could not read cached plaintext", errorText(e));
  }
}

export function getGroupStatus(channelId: string | null): OmnidiscGroupStatus | null {
  return channelId ? (groupStatusByChannel[channelId] ?? null) : null;
}

export async function refreshGroupStatus(channelId: string) {
  const instance = instanceForChannel(channelId);
  if (!instance || isDemo(instance.id) || !isEncryptedChannel(channelId)) return;
  try {
    const raw = await invoke<unknown>("omnidisc_mls_status", { url: instance.url, channelId });
    if (!isRecord(raw)) return;
    const members = (Array.isArray(raw.members) ? raw.members : [])
      .filter(isRecord)
      .map((m) => ({
        userId: str(m.user_id) ?? "",
        deviceId: str(m.device_id) ?? "",

View on GitHub (pinned to 8600b91f42)