chatboxai/chatbox · error · Error
Unmatching product
Error message
Unmatching product
What it means
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.
Source
Thrown at src/renderer/packages/lemonsqueezy.ts:58
license_key: key,
instance_name: instanceName,
}),
})
const json: ActivateResponse = await res.json()
if (!json.activated) {
if (json.error.includes('This license key has reached the activation limit') && json.license_key) {
return { valid: false, instanceId: '', error: 'reached_activation_limit' }
} else if (json.error.includes('This license key is expired.')) {
return { valid: false, instanceId: '', error: 'expired' }
} else if (json.error.includes('license_key not found')) {
return { valid: false, instanceId: '', error: 'not_found' }
} else {
throw new Error(json.error)
}
}
const remoteConfig = await remote.getRemoteConfig('product_ids')
if (!remoteConfig.product_ids.includes(json.meta.product_id)) {
throw new Error('Unmatching product')
}
return { valid: true, instanceId: json.instance.id }
}
export async function deactivateLicense(key: string, instanceId: string) {
await ofetch('https://api.lemonsqueezy.com/v1/licenses/deactivate', {
method: 'POST',
retry: 5,
body: {
license_key: key,
instance_id: instanceId,
},
})
}
type ValidateLicenseKeyResponse = {
valid: boolean
}View on GitHub (pinned to 81571269ad)
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.
Defensive patterns
Strategy: try-catch
Validate before calling
const allowedProductIds = (await remote.getRemoteConfig('product_ids')).product_ids
// cannot fully pre-validate without the key's product_id, but ensure remote config loaded:
if (!allowedProductIds?.length) console.warn('product_ids remote config missing; mismatch error likely') Type guard
function isLemonsqueezyActivationResponse(json: unknown): json is { meta: { product_id: number }; instance: { id: string } } {
return !!json && typeof json === 'object' &&
typeof (json as any).meta?.product_id === 'number' &&
typeof (json as any).instance?.id === 'string'
} Try / catch
try {
await activateLicense(key)
} catch (e) {
if (e instanceof Error && e.message === 'Unmatching product') {
// tell user the key is for a different product; ask for the correct key
}
throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- A license key is required to claim the Agent Mode reward
- License key is required for image generation
- License validation response was not understood
- No readable text content found in EPUB file
- Embedding batch failed: expected ${batchTexts.length}, got $
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/9bea14a28bf5a6c9.
Report an issue: GitHub.