{"record":{"id":"ff53ea9e8dd651f0","repo":"Stirling-Tools/Stirling-PDF","slug":"no-valid-license-found-please-purchase-a-license","errorCode":null,"errorMessage":"No valid license found. Please purchase a license before accessing the billing portal.","messagePattern":"No valid license found\\. Please purchase a license before accessing the billing portal\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"frontend/editor/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx","lineNumber":66,"sourceCode":"    { value: \"gbp\", label: \"British pound (GBP, £)\" },\n    { value: \"usd\", label: \"US dollar (USD, $)\" },\n    { value: \"eur\", label: \"Euro (EUR, €)\" },\n    { value: \"cny\", label: \"Chinese yuan (CNY, ¥)\" },\n    { value: \"inr\", label: \"Indian rupee (INR, ₹)\" },\n    { value: \"brl\", label: \"Brazilian real (BRL, R$)\" },\n    { value: \"idr\", label: \"Indonesian rupiah (IDR, Rp)\" },\n  ];\n\n  const handleManageClick = useCallback(async () => {\n    // Block access if login is disabled\n    if (!validateLoginEnabled()) {\n      return;\n    }\n\n    try {\n      // Only allow PRO or ENTERPRISE licenses to access billing portal\n      if (!licenseInfo?.licenseType || licenseInfo.licenseType === \"NORMAL\") {\n        throw new Error(\n          \"No valid license found. Please purchase a license before accessing the billing portal.\",\n        );\n      }\n\n      if (!licenseInfo?.licenseKey) {\n        throw new Error(\"License key missing. Please contact support.\");\n      }\n\n      // Create billing portal session with license key\n      const response = await licenseService.createBillingPortalSession(\n        window.location.href,\n        licenseInfo.licenseKey,\n      );\n\n      // Open billing portal in new tab\n      window.open(response.url, \"_blank\");\n    } catch (error: unknown) {\n      console.error(\"Failed to open billing portal:\", error);","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx#L48-L84","documentation":"Thrown by AdminPlanSection.handleManageClick when the user's license is absent, falsy, or 'NORMAL' (free tier). Only PRO or ENTERPRISE licenses are permitted to open the billing portal — the portal is for managing paid subscriptions, not for free-tier users.","triggerScenarios":"User with no licenseType, a falsy licenseType, or licenseType === 'NORMAL' clicks the Manage Billing control in the admin plan section.","commonSituations":"A free/NORMAL user reaches the admin config and tries to manage billing. License info failed to load (undefined). User downgraded to free and the cached licenseType is stale.","solutions":["Hide the Manage Billing control entirely when licenseType is missing or 'NORMAL'.","Show an 'Upgrade' CTA instead of the Manage Billing button for free-tier users.","Ensure licenseInfo is loaded and refreshed before rendering the section."],"exampleFix":"// before\nif (!licenseInfo?.licenseType || licenseInfo.licenseType === \"NORMAL\") {\n  throw new Error(\"No valid license found. ...\");\n}\n\n// after — gate the UI\nconst canManageBilling =\n  !!licenseInfo?.licenseType && licenseInfo.licenseType !== \"NORMAL\";\nreturn canManageBilling ? <ManageBillingButton /> : <UpgradePrompt />;","handlingStrategy":"validation","validationCode":"const isPaidLicense =\n  !!licenseInfo?.licenseType &&\n  licenseInfo.licenseType !== \"NORMAL\";\n// Only render Manage Billing when isPaidLicense is true","typeGuard":"function isPaidLicenseType(type: unknown): boolean {\n  return typeof type === \"string\" && type !== \"NORMAL\" && type.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Render Manage Billing only for PRO/ENTERPRISE licenses.","Show an Upgrade CTA for free-tier users instead.","Ensure licenseInfo is loaded before rendering the section."],"tags":["license","billing","validation","proprietary","admin"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}