{"record":{"id":"81382200e2642fc2","repo":"Stirling-Tools/Stirling-PDF","slug":"no-license-key-found-please-activate-a-license-fi","errorCode":null,"errorMessage":"No license key found. Please activate a license first.","messagePattern":"No license key found\\. Please activate a license first\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"frontend/editor/src/proprietary/components/shared/ManageBillingButton.tsx","lineNumber":25,"sourceCode":"interface ManageBillingButtonProps {\n  returnUrl?: string;\n}\n\nexport const ManageBillingButton: React.FC<ManageBillingButtonProps> = ({\n  returnUrl = window.location.href,\n}) => {\n  const { t } = useTranslation();\n  const [loading, setLoading] = useState(false);\n\n  const handleClick = async () => {\n    try {\n      setLoading(true);\n\n      // Get current license key for authentication\n      const licenseInfo = await licenseService.getLicenseInfo();\n\n      if (!licenseInfo.licenseKey) {\n        throw new Error(\n          \"No license key found. Please activate a license first.\",\n        );\n      }\n\n      // Create billing portal session with license key\n      const response = await licenseService.createBillingPortalSession(\n        returnUrl,\n        licenseInfo.licenseKey,\n      );\n\n      // Open billing portal in new tab\n      window.open(response.url, \"_blank\");\n      setLoading(false);\n    } catch (error: unknown) {\n      console.error(\"Failed to open billing portal:\", error);\n      alert({\n        alertType: \"error\",\n        title: t(\"billing.portal.error\", \"Failed to open billing portal\"),","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/proprietary/components/shared/ManageBillingButton.tsx#L7-L43","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Hide or disable the Manage Billing button when no license key is present (check license info on mount).","Redirect the user to the license activation flow before showing the billing button.","On error, guide the user to activate a license first with a link/button to the activation page."],"exampleFix":"// before\nconst licenseInfo = await licenseService.getLicenseInfo();\nif (!licenseInfo.licenseKey) {\n  throw new Error(\"No license key found. Please activate a license first.\");\n}\n\n// after — disable the button reactively and show activation prompt\nconst { licenseKey } = useLicenseInfo(); // hook reading license store\nreturn (\n  <Button disabled={!licenseKey} onClick={handleClick}>\n    {licenseKey ? t(\"billing.manageBilling\") : t(\"billing.activateLicense\")}\n  </Button>\n);","handlingStrategy":"validation","validationCode":"// Load license info reactively and disable the button when no key\nconst { licenseInfo } = useLicense();\nconst hasKey = !!licenseInfo?.licenseKey;\n<Button disabled={!hasKey} ...>","typeGuard":"function hasLicenseKey(info: unknown): boolean {\n  return !!info && typeof info === \"object\" && !!(info as { licenseKey?: unknown }).licenseKey;\n}","tryCatchPattern":null,"preventionTips":["Gate the billing button on license presence before the click handler runs.","Redirect unlicensed users to the activation flow.","Refresh license info on mount to avoid stale empty state."],"tags":["license","billing","validation","proprietary"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}