Stirling-Tools/Stirling-PDF · warning · Error

No license key found. Please activate a license first.

Error message

No license key found. Please activate a license first.

What it means

Thrown by ManageBillingButton when licenseService.getLicenseInfo() returns an object whose licenseKey is falsy. The button assumes a license key exists to authenticate the billing-portal session creation; without one, the portal session cannot be created.

Source

Thrown at frontend/editor/src/proprietary/components/shared/ManageBillingButton.tsx:25

interface ManageBillingButtonProps {
  returnUrl?: string;
}

export const ManageBillingButton: React.FC<ManageBillingButtonProps> = ({
  returnUrl = window.location.href,
}) => {
  const { t } = useTranslation();
  const [loading, setLoading] = useState(false);

  const handleClick = async () => {
    try {
      setLoading(true);

      // Get current license key for authentication
      const licenseInfo = await licenseService.getLicenseInfo();

      if (!licenseInfo.licenseKey) {
        throw new Error(
          "No license key found. Please activate a license first.",
        );
      }

      // Create billing portal session with license key
      const response = await licenseService.createBillingPortalSession(
        returnUrl,
        licenseInfo.licenseKey,
      );

      // Open billing portal in new tab
      window.open(response.url, "_blank");
      setLoading(false);
    } catch (error: unknown) {
      console.error("Failed to open billing portal:", error);
      alert({
        alertType: "error",
        title: t("billing.portal.error", "Failed to open billing portal"),

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Hide or disable the Manage Billing button when no license key is present (check license info on mount).
  2. Redirect the user to the license activation flow before showing the billing button.
  3. On error, guide the user to activate a license first with a link/button to the activation page.

Example fix

// before
const licenseInfo = await licenseService.getLicenseInfo();
if (!licenseInfo.licenseKey) {
  throw new Error("No license key found. Please activate a license first.");
}

// after — disable the button reactively and show activation prompt
const { licenseKey } = useLicenseInfo(); // hook reading license store
return (
  <Button disabled={!licenseKey} onClick={handleClick}>
    {licenseKey ? t("billing.manageBilling") : t("billing.activateLicense")}
  </Button>
);
Defensive patterns

Strategy: validation

Validate before calling

// Load license info reactively and disable the button when no key
const { licenseInfo } = useLicense();
const hasKey = !!licenseInfo?.licenseKey;
<Button disabled={!hasKey} ...>

Type guard

function hasLicenseKey(info: unknown): boolean {
  return !!info && typeof info === "object" && !!(info as { licenseKey?: unknown }).licenseKey;
}

Prevention

When it happens

Trigger: User clicks Manage Billing before activating any license. The license store is empty/cleared (fresh install, logged out, local storage wiped). getLicenseInfo() resolved but licenseKey was null/empty string.

Common situations: Self-hosted/desktop user without an activated license. License data was cleared from storage. A free-tier user with no purchase attempting to reach the billing portal.

Related errors


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