Stirling-Tools/Stirling-PDF · error · Error
This operation (${endpointToCheck}) is not available. It may
Error message
This operation (${endpointToCheck}) is not available. It may require a self-hosted instance with additional features enabled. What it means
Thrown by OperationRouter.getBaseUrlForOperation() in SaaS mode after a two-stage capability probe fails on BOTH backends. The router first asks endpointAvailabilityService.isEndpointSupportedLocally() (probes the bundled Tauri backend) and, on a miss, asks isEndpointSupportedOnSaaS() (probes the hosted SaaS backend). Only when both return false is the operation declared unsupported. The endpoint name passed in is extracted from the operation path (e.g. '/api/v1/misc/repair' -> 'repair') via extractEndpointName().
Source
Thrown at frontend/editor/src/desktop/services/operationRouter.ts:233
`[operationRouter] Endpoint ${endpointToCheck} supported locally: ${supportedLocally}`,
);
if (!supportedLocally) {
// Local backend doesn't support this - check if SaaS supports it
const supportedOnSaaS =
await endpointAvailabilityService.isEndpointSupportedOnSaaS(
endpointToCheck,
);
console.debug(
`[operationRouter] Endpoint ${endpointToCheck} supported on SaaS: ${supportedOnSaaS}`,
);
if (!supportedOnSaaS) {
// Neither local nor SaaS support this - throw error
console.error(
`[operationRouter] Endpoint ${endpointToCheck} not supported on local or SaaS backend`,
);
throw new Error(
`This operation (${endpointToCheck}) is not available. It may require a self-hosted instance with additional features enabled.`,
);
}
// SaaS supports it - route to SaaS backend
if (!STIRLING_SAAS_BACKEND_API_URL) {
console.error(
"[operationRouter] VITE_SAAS_BACKEND_API_URL not configured",
);
throw new Error(
"Cloud processing is required for this tool but VITE_SAAS_BACKEND_API_URL is not configured. " +
"Please check your environment configuration.",
);
}
console.debug(
`[operationRouter] Routing ${operation} to SaaS backend (not supported locally, but supported on SaaS)`,
);
return STIRLING_SAAS_BACKEND_API_URL.replace(/\/$/, "");View on GitHub (pinned to 9ef20dcab8)
Solutions
- Confirm the real endpoint name: log extractEndpointName(operation) and compare it against the entry each backend advertises in its capability/feature list.
- If the feature is self-hosted-only, switch the app to self-hosted mode (or run a self-hosted instance with the feature enabled) instead of SaaS mode.
- If the SaaS backend should support it, verify the SaaS capability source (isEndpointSupportedOnSaaS) is reachable and returns the endpoint in its supported list.
- If the local bundled backend should support it, verify the local backend is the expected build/variant (ultra-lite strips endpoints) and its endpoint registry includes the operation.
- As a last resort, disable the tool in the frontend tool registry until at least one backend supports it, so users never reach this throw.
Example fix
// before — throw is the only outcome when neither backend supports it
if (!supportedOnSaaS) {
throw new Error(`This operation (${endpointToCheck}) is not available...`);
}
// after — surface a typed, user-facing 'unsupported' result the UI can render
// instead of an uncaught throw, so callers can show a disabled-state badge
throw new OperationUnsupportedError(endpointToCheck, { locally: supportedLocally, saas: supportedOnSaaS }); Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check both backends before routing, so unsupported tools never throw
import { endpointAvailabilityService } from "@app/desktop/services/endpointAvailabilityService";
import { tauriBackendService } from "@app/desktop/services/tauriBackendService";
async function isOperationAvailable(endpointName: string): Promise<boolean> {
const localUrl = tauriBackendService.getBackendUrl();
const localOk = localUrl && tauriBackendService.isOnline
? await endpointAvailabilityService.isEndpointSupportedLocally(endpointName, localUrl)
: false;
if (localOk) return true;
return endpointAvailabilityService.isEndpointSupportedOnSaaS(endpointName);
} Type guard
export class OperationUnsupportedError extends Error {
constructor(public readonly endpoint: string, opts: { locally: boolean; saas: boolean }) {
super(`Operation ${endpoint} not available (local=${opts.locally}, saas=${opts.saas})`);
this.name = "OperationUnsupportedError";
}
}
function isOperationUnsupportedError(e: unknown): e is OperationUnsupportedError {
return e instanceof Error && /is not available/.test(e.message);
} Try / catch
try {
const base = await router.getBaseUrlForOperation(operation);
} catch (e) {
if (isOperationUnsupportedError(e)) { showToolDisabled(e.endpoint); return; }
throw e;
} Prevention
- Probe capability with endpointAvailabilityService before enabling a tool in the UI.
- Log extractEndpointName(operation) in dev to catch extraction mismatches early.
- Keep the frontend tool registry in sync with the backend's advertised capability list.
When it happens
Trigger: SaaS mode + the operation is a tool endpoint (isToolEndpoint true) + the local bundled backend is healthy and online (backendUrl && backendHealthy) + isEndpointSupportedLocally(endpointToCheck, backendUrl) === false AND isEndpointSupportedOnSaaS(endpointToCheck) === false. Reachable only when the local backend is actually up, because a not-yet-ready backend skips the check and falls through to local routing.
Common situations: The operation requires a proprietary/self-hosted-only feature flag that is disabled in this SaaS build; the endpoint name extraction strips a path segment the capability registry does not recognise; the SaaS backend's capability list is stale or the local registry endpoint returns an unexpected shape so both probes parse as 'unsupported'; a brand-new tool whose endpoint was added to the frontend before either backend shipped support.
Related errors
- Your Stirling-PDF server is offline and "{{endpoint}}" is no
- Sign up failed
- Server configuration not found
- Failed to save authentication token
- Cannot connect to server. Please check the server URL and en
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/88f1e4b40b9a2b7a.
Report an issue: GitHub.