Stirling-Tools/Stirling-PDF · warning · Error

Connection mode is locked by provisioning

Error message

Connection mode is locked by provisioning

What it means

Thrown by connectionModeService.switchToSaaS when currentConfig.lock_connection_mode is true. This flag is set by provisioning (e.g. an MSI install pinned with STIRLING_SERVER_URL) to forbid the user from changing the connection target away from the provisioned server. The mode switch is rejected before any Rust command runs.

Source

Thrown at frontend/editor/src/desktop/services/connectionModeService.ts:139

      this.currentConfig = config;
      this.configLoadedOnce = true;
    } catch (error) {
      console.error("Failed to load connection config:", error);
      // Default to local mode on error — safer than showing SaaS UI for a
      // desktop app whose bundled backend is always available.
      this.currentConfig = {
        mode: "local",
        server_config: null,
        lock_connection_mode: false,
      };
      this.configLoadedOnce = true;
    }
  }

  async switchToSaaS(saasServerUrl: string): Promise<void> {
    if (this.currentConfig?.lock_connection_mode) {
      throw new Error("Connection mode is locked by provisioning");
    }

    // Clear local-only flag and expiry-prompted flag when signing in
    localStorage.removeItem(LOCAL_MODE_STORAGE_KEY);
    localStorage.removeItem(JWT_EXPIRED_PROMPTED_KEY);

    console.log("Switching to SaaS mode");

    const previousMode = this.currentConfig?.mode ?? null;
    const serverConfig: ServerConfig = { url: saasServerUrl };

    await invoke("set_connection_mode", {
      mode: "saas",
      serverConfig,
    });

    this.currentConfig = {
      mode: "saas",

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Do not call switchToSaaS on locked installs — check currentConfig.lock_connection_mode first and hide/disable the SaaS switch UI.
  2. If a different server is genuinely required, have the admin re-provision the install with the new STIRLING_SERVER_URL (clearing the lock).
  3. Surface a clear 'managed by your administrator' message instead of a raw error.

Example fix

// before
await connectionModeService.switchToSaaS(url);

// after: respect the lock
const cfg = await connectionModeService.getCurrentConfig();
if (cfg.lock_connection_mode) {
  notify('Connection mode is managed by your administrator.');
  return;
}
await connectionModeService.switchToSaaS(url);
Defensive patterns

Strategy: validation

Validate before calling

const cfg = await connectionModeService.getCurrentConfig();
if (cfg.lock_connection_mode) { notify('Connection mode is managed by your administrator.'); return; }

Type guard

function isConnectionModeLocked(e: unknown): e is Error {
  return e instanceof Error && e.message === 'Connection mode is locked by provisioning';
}

Try / catch

try { await connectionModeService.switchToSaaS(url); }
catch (e) {
  if (isConnectionModeLocked(e)) { notify('Connection mode is managed by your administrator.'); return; }
  throw e;
}

Prevention

When it happens

Trigger: A provisioned/managed desktop install where the admin locked connection mode, and the user (or a code path) calls switchToSaaS(). The provisioned config sets lock_connection_mode: true at load time.

Common situations: Enterprise MSI deployment with a fixed server URL; kiosk/single-tenant setup; code that auto-prompts 'sign in to Cloud' hitting a locked install.

Related errors


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