{"record":{"id":"c75cb28e440b97a9","repo":"Stirling-Tools/Stirling-PDF","slug":"backend-url-not-available-backend-may-still-be-s","errorCode":null,"errorMessage":"Backend URL not available - backend may still be starting","messagePattern":"Backend URL not available - backend may still be starting","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"frontend/editor/src/desktop/services/operationRouter.ts","lineNumber":176,"sourceCode":"          if (!supportedLocally) {\n            // Open the connection settings so the user can sign in\n            window.dispatchEvent(\n              new CustomEvent(\"appConfig:navigate\", {\n                detail: { key: \"connectionMode\" },\n              }),\n            );\n            throw new Error(\n              i18n.t(\n                \"localMode.toolUnavailable\",\n                \"This tool requires an account. Sign in to Stirling Cloud or connect to a self-hosted server to use it.\",\n              ),\n            );\n          }\n        }\n      }\n      const backendUrl = tauriBackendService.getBackendUrl();\n      if (!backendUrl) {\n        throw new Error(\n          \"Backend URL not available - backend may still be starting\",\n        );\n      }\n      return backendUrl.replace(/\\/$/, \"\");\n    }\n\n    // Always route team endpoints to SaaS backend (existing logic)\n    if (mode === \"saas\" && this.isSaaSBackendEndpoint(operation)) {\n      if (!STIRLING_SAAS_BACKEND_API_URL) {\n        throw new Error(\"VITE_SAAS_BACKEND_API_URL not configured\");\n      }\n      console.debug(\n        `[operationRouter] Routing ${operation} to SaaS backend (team endpoint)`,\n      );\n      return STIRLING_SAAS_BACKEND_API_URL.replace(/\\/$/, \"\");\n    }\n\n    // NEW: Check if local backend supports this tool endpoint","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/desktop/services/operationRouter.ts#L158-L194","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Wait for the backend-readiness signal (tauriBackendService.isOnline / the health check) before enabling tool actions.","Retry the operation after a short delay or once the backend-online event fires.","If it persists, check the backend logs — the JVM may have failed to start (port in use, missing resources).","Ensure no other process has already taken the backend's port."],"exampleFix":"// before: fire on mount\nuseEffect(() => { runTool(); }, []);\n\n// after: wait for the bundled backend to be ready\nuseEffect(() => {\n  if (!tauriBackendService.isOnline) return; // wait for readiness event\n  runTool();\n}, [tauriBackendService.isOnline]);","handlingStrategy":"retry","validationCode":"// wait for the bundled backend before enabling tool actions\nif (!tauriBackendService.getBackendUrl() || !tauriBackendService.isOnline) {\n  show('Starting the local backend…');\n  await waitForBackendOnline();\n}","typeGuard":"function isBackendNotReady(e: unknown): e is Error {\n  return e instanceof Error && /Backend URL not available/.test(e.message);\n}","tryCatchPattern":"async function runWhenReady(op: () => Promise<void>) {\n  try { await op(); }\n  catch (e) {\n    if (isBackendNotReady(e)) { await waitForBackendOnline(); return op(); }\n    throw e;\n  }\n}","preventionTips":["Gate tool actions on tauriBackendService.isOnline / the backend-health signal.","Retry once the backend-online event fires rather than polling blindly.","Log backend startup failures early so a crashed JVM is visible."],"tags":["local-mode","backend-startup","timing","routing","desktop"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}