Stirling-Tools/Stirling-PDF · warning · Error

Backend URL not available - backend may still be starting

Error message

Backend URL not available - backend may still be starting

What it means

Thrown by operationRouter.getBaseUrl in local mode when tauriBackendService.getBackendUrl() returns a falsy value — the bundled local backend has not yet announced its URL/port. This is a startup-timing issue: the backend process is still launching when an operation was requested.

Source

Thrown at frontend/editor/src/desktop/services/operationRouter.ts:176

          if (!supportedLocally) {
            // Open the connection settings so the user can sign in
            window.dispatchEvent(
              new CustomEvent("appConfig:navigate", {
                detail: { key: "connectionMode" },
              }),
            );
            throw new Error(
              i18n.t(
                "localMode.toolUnavailable",
                "This tool requires an account. Sign in to Stirling Cloud or connect to a self-hosted server to use it.",
              ),
            );
          }
        }
      }
      const backendUrl = tauriBackendService.getBackendUrl();
      if (!backendUrl) {
        throw new Error(
          "Backend URL not available - backend may still be starting",
        );
      }
      return backendUrl.replace(/\/$/, "");
    }

    // Always route team endpoints to SaaS backend (existing logic)
    if (mode === "saas" && this.isSaaSBackendEndpoint(operation)) {
      if (!STIRLING_SAAS_BACKEND_API_URL) {
        throw new Error("VITE_SAAS_BACKEND_API_URL not configured");
      }
      console.debug(
        `[operationRouter] Routing ${operation} to SaaS backend (team endpoint)`,
      );
      return STIRLING_SAAS_BACKEND_API_URL.replace(/\/$/, "");
    }

    // NEW: Check if local backend supports this tool endpoint

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Wait for the backend-readiness signal (tauriBackendService.isOnline / the health check) before enabling tool actions.
  2. Retry the operation after a short delay or once the backend-online event fires.
  3. If it persists, check the backend logs — the JVM may have failed to start (port in use, missing resources).
  4. Ensure no other process has already taken the backend's port.

Example fix

// before: fire on mount
useEffect(() => { runTool(); }, []);

// after: wait for the bundled backend to be ready
useEffect(() => {
  if (!tauriBackendService.isOnline) return; // wait for readiness event
  runTool();
}, [tauriBackendService.isOnline]);
Defensive patterns

Strategy: retry

Validate before calling

// wait for the bundled backend before enabling tool actions
if (!tauriBackendService.getBackendUrl() || !tauriBackendService.isOnline) {
  show('Starting the local backend…');
  await waitForBackendOnline();
}

Type guard

function isBackendNotReady(e: unknown): e is Error {
  return e instanceof Error && /Backend URL not available/.test(e.message);
}

Try / catch

async function runWhenReady(op: () => Promise<void>) {
  try { await op(); }
  catch (e) {
    if (isBackendNotReady(e)) { await waitForBackendOnline(); return op(); }
    throw e;
  }
}

Prevention

When it happens

Trigger: An API call is made before the bundled Java backend has finished starting and registered its URL with the Rust side. The Axios interceptor's backend-readiness check may also not yet have blocked it.

Common situations: First seconds after app launch when the user clicks a tool immediately; a slow machine where the JVM takes longer to boot; the backend crashed during startup so it never registers a URL.

Related errors


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