Stirling-Tools/Stirling-PDF · error · Error

Failed to save authentication token

Error message

Failed to save authentication token

What it means

Thrown by AuthService.login after the Rust 'login' invoke command already returned a valid token+refresh_token, but saveTokenEverywhere() failed to persist the token into the Tauri secure store / localStorage. The login was successful server-side; only local persistence failed. The underlying storage-layer error is preserved as error.cause, and auth status is NOT changed by this throw (the outer catch will reset it to unauthenticated).

Source

Thrown at frontend/editor/src/desktop/services/authService.ts:365

        supabaseKey: SUPABASE_KEY,
        saasServerUrl: STIRLING_SAAS_URL,
      });

      const {
        token,
        username: returnedUsername,
        email,
        refresh_token: refreshToken,
      } = response;

      // Save token to all storage locations. Supabase (SaaS) logins include a
      // refresh token so the short-lived access token can be renewed; self-hosted
      // logins return null here and refresh via the current access token instead.
      try {
        await this.saveTokenEverywhere(token, refreshToken);
      } catch (error) {
        console.error("[Desktop AuthService] Failed to save token:", error);
        throw new Error("Failed to save authentication token", {
          cause: error,
        });
      }

      // Save user info to store
      await invoke("save_user_info", {
        username: returnedUsername || username,
        email,
      });

      const userInfo: UserInfo = {
        username: returnedUsername || username,
        email: email || undefined,
      };

      this.setAuthStatus("authenticated", userInfo);

      return userInfo;

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Inspect error.cause for the real storage-layer message (Tauri store write vs keyring access) and fix that specific layer.
  2. On Linux, ensure a secret-service implementation (gnome-keyring / kwallet) is running and unlocked before launching the app.
  3. Clear a corrupted store: remove the Tauri store file and localStorage key 'stirling_jwt', then retry login.
  4. If the keyring is permanently unavailable, reinstall the desktop app so the Tauri store/keyring plugins re-register.
  5. Free disk space on the volume holding the OS temp / app-data directory.

Example fix

// before: caller sees only the generic message
try { await authService.login(...); }
catch (e) { showError(e.message); }

// after: surface the real storage cause and offer retry
try { await authService.login(...); }
catch (e) {
  if (e instanceof Error && e.message === 'Failed to save authentication token') {
    showError(`Could not store your login: ${e.cause instanceof Error ? e.cause.message : e.cause}`);
    offerRetry();
    return;
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Type guard

function isTokenSaveFailure(e: unknown): e is Error & { cause: unknown } {
  return e instanceof Error && e.message === 'Failed to save authentication token';
}

Try / catch

try { await authService.login(server, user, pass); }
catch (e) {
  if (isTokenSaveFailure(e)) {
    // login worked server-side; only local persistence failed -> safe to retry login
    const cause = e instanceof Error ? (e as any).cause : undefined;
    reportStorageError(cause);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: saveTokenEverywhere(token, refreshToken) rejects. Concretely: the Tauri store plugin command fails to write, the OS keyring/credential store is locked or missing, the store JSON is corrupted, the disk is full, or a keychain permission prompt was declined.

Common situations: Running on a headless/CI Linux box with no secret-service daemon; a corporate machine where the login keychain is locked at the moment of login; a corrupted stirling_jwt / Tauri store file left from an older app version; disk-full on the volume holding the Tauri app data dir.

Understand the failure class

Related errors


AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13). Data as JSON: /api/errors/dfada1905d3dce1e. Report an issue: GitHub.