{"record":{"id":"9bea14a28bf5a6c9","repo":"chatboxai/chatbox","slug":"unmatching-product","errorCode":null,"errorMessage":"Unmatching product","messagePattern":"Unmatching product","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/packages/lemonsqueezy.ts","lineNumber":58,"sourceCode":"      license_key: key,\n      instance_name: instanceName,\n    }),\n  })\n  const json: ActivateResponse = await res.json()\n  if (!json.activated) {\n    if (json.error.includes('This license key has reached the activation limit') && json.license_key) {\n      return { valid: false, instanceId: '', error: 'reached_activation_limit' }\n    } else if (json.error.includes('This license key is expired.')) {\n      return { valid: false, instanceId: '', error: 'expired' }\n    } else if (json.error.includes('license_key not found')) {\n      return { valid: false, instanceId: '', error: 'not_found' }\n    } else {\n      throw new Error(json.error)\n    }\n  }\n  const remoteConfig = await remote.getRemoteConfig('product_ids')\n  if (!remoteConfig.product_ids.includes(json.meta.product_id)) {\n    throw new Error('Unmatching product')\n  }\n  return { valid: true, instanceId: json.instance.id }\n}\n\nexport async function deactivateLicense(key: string, instanceId: string) {\n  await ofetch('https://api.lemonsqueezy.com/v1/licenses/deactivate', {\n    method: 'POST',\n    retry: 5,\n    body: {\n      license_key: key,\n      instance_id: instanceId,\n    },\n  })\n}\n\ntype ValidateLicenseKeyResponse = {\n  valid: boolean\n}","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/packages/lemonsqueezy.ts#L40-L76","documentation":"Thrown by the Lemonsqueezy license validator after a license key validates successfully against the Lemonsqueezy API, but the returned meta.product_id is not in the product_ids list fetched from the app's remote config. It prevents a valid-but-wrong-product key (e.g. a key for a different app/SKU) from granting entitlements in this product.","triggerScenarios":"activateLicense/checkLicense succeeds at the Lemonsqueezy layer, then `remoteConfig.product_ids.includes(json.meta.product_id)` is false. Common when a user pastes a license key bought for a different product/bundle.","commonSituations":"User owns multiple Lemonsqueezy products and pastes the wrong key; remote config product_ids was updated but the user's cached key is from a legacy product; a resold/shared key is for a different SKU.","solutions":["Verify the license key is the one issued for THIS product (check the purchase email/product name).","Ensure the device is online so remote config product_ids is current — a stale/empty list can exclude a valid product_id.","If remote config is correct and the key is genuinely for this product, contact support to reconcile the product_id mapping."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const allowedProductIds = (await remote.getRemoteConfig('product_ids')).product_ids\n// cannot fully pre-validate without the key's product_id, but ensure remote config loaded:\nif (!allowedProductIds?.length) console.warn('product_ids remote config missing; mismatch error likely')","typeGuard":"function isLemonsqueezyActivationResponse(json: unknown): json is { meta: { product_id: number }; instance: { id: string } } {\n  return !!json && typeof json === 'object' &&\n    typeof (json as any).meta?.product_id === 'number' &&\n    typeof (json as any).instance?.id === 'string'\n}","tryCatchPattern":"try {\n  await activateLicense(key)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Unmatching product') {\n    // tell user the key is for a different product; ask for the correct key\n  }\n  throw e\n}","preventionTips":["Show the product name the key was issued for at purchase time.","Cache product_ids remote config and warn early if the key's product isn't listed.","Distinguish this error from network errors so users aren't told to retry."],"tags":["license","lemonsqueezy","validation","entitlement"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}