{"record":{"id":"dfc7fd179f029193","repo":"mastra-ai/mastra","slug":"license-server-rate-limited-data-reason","errorCode":null,"errorMessage":"License server rate limited: ${data.reason}","messagePattern":"License server rate limited: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/core/src/license/index.ts","lineNumber":187,"sourceCode":"      }\n\n      const data = (await response.json()) as LicenseValidationResponse;\n\n      if (data.valid) {\n        this.status = 'valid';\n        this.logger?.info(`License validated${data.expiresAt ? `, expires ${data.expiresAt.slice(0, 10)}` : ''}`);\n        this.cachedResult = data;\n\n        const ttlSeconds = data.leaseTtlSeconds || this.DEFAULT_TTL_MS / 1000;\n        this.cacheExpiry = now + ttlSeconds * 1000;\n        this.gracePeriodEnd = now + this.GRACE_PERIOD_MS;\n\n        this.scheduleRevalidation(ttlSeconds);\n        return true;\n      } else if (data.code === 'RATE_LIMITED') {\n        // Defensive: a throttle marker in the body without a 429 status is\n        // still transient, not a license verdict.\n        throw new Error(`License server rate limited: ${data.reason}`);\n      } else {\n        this.status = 'invalid';\n        this.logger?.error(`License validation failed: ${data.code} - ${data.reason}`);\n        this.clearCache();\n        return false;\n      }\n    } catch {\n      // Network error or server unreachable\n      if (this.cachedResult && now < this.gracePeriodEnd) {\n        this.logger?.warn('License server unreachable. Using cached license (within grace period).');\n        this.status = 'valid';\n        this.scheduleRevalidation(this.DEFAULT_TTL_MS / 1000); // Retry later\n        return true;\n      } else if (this.cachedResult) {\n        this.logger?.error('License server unreachable and grace period expired. Disabling enterprise features.');\n        this.status = 'invalid';\n        this.clearCache();\n        return false;","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/license/index.ts#L169-L205","documentation":"If the license validation response body carries code 'RATE_LIMITED' without an HTTP 429 status, performValidation throws 'License server rate limited: <reason>'. The source comment marks this as defensive: a throttle marker in the body is still a transient condition, not a verdict on the license, so it throws rather than marking the key invalid (which is what happens for INVALID_KEY/EXPIRED/REVOKED).","triggerScenarios":"The license server responds 200 (or another non-429 status) but the JSON body contains valid:false, code:'RATE_LIMITED' — an inconsistent server response or intermediary stripping/rewriting status codes — while the client is exceeding validation request limits.","commonSituations":"A reverse proxy or API gateway collapsing error statuses into 200 responses; many processes/containers validating the same key concurrently and hitting server-side throttling; aggressive revalidation loops in a fleet of workers.","solutions":["Back off and retry — RATE_LIMITED is transient; the key itself is fine","Reduce validation frequency: cache the lease for the full leaseTtlSeconds and avoid tight revalidation loops","Consolidate license checks: run one validator per host/pod and share the result internally","Inspect proxies/gateways between client and license server that may mangle HTTP status codes"],"exampleFix":"// before\nwhile (true) { await license.performValidation(); } // hammers server -> RATE_LIMITED\n// after\ntry {\n  await license.performValidation();\n} catch (e) {\n  if (String(e).includes('rate limited')) {\n    await new Promise(r => setTimeout(r, 30_000)); // back off, then retry\n    await license.performValidation();\n  }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await licenseClient.validate();\n} catch (e) {\n  if (e.message.startsWith('License server rate limited')) {\n    await new Promise(r => setTimeout(r, 30_000)); // exponential backoff\n    await licenseClient.validate();\n  } else {\n    throw e;\n  }\n}","preventionTips":["Cache validation results for the full leaseTtlSeconds","Avoid tight revalidation loops in fleets of workers","One validator per host/pod; share the verdict internally","Check for gateways/proxies that rewrite HTTP statuses to 200"],"tags":["license","rate-limit","throttling","transient"],"backgroundTag":"rate-limited","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}