risingwavelabs/risingwave · error · LicenseError
invalid license key
Error message
invalid license key
What it means
LicenseError::InvalidKey is returned when the license key set for the RisingWave cluster cannot be verified as a valid JWT. LicenseManager::refresh decodes the key with the embedded RSA public key (RS512) and issuer validation; any jsonwebtoken error (bad signature, expired, wrong issuer, malformed token) becomes InvalidKey with the underlying jsonwebtoken::errors::Error as its source. license() also returns this variant when the key has passed its `exp` claim.
Source
Thrown at src/license/src/manager.rs:202
impl Default for License {
/// The default license is a free license that never expires.
///
/// Used when `license_key` is unset or invalid.
fn default() -> Self {
Self {
sub: "default".to_owned(),
tier: Tier::Free,
iss: Issuer::Prod,
rwu_limit: None,
exp: u64::MAX,
}
}
}
/// The error type for invalid license key when verifying as JWT.
#[derive(Debug, Clone, Error)]
pub enum LicenseError {
#[error("invalid license key")]
InvalidKey(#[source] jsonwebtoken::errors::Error),
#[error(
"a valid license key is set, but it is currently not effective because the CPU core in the cluster \
({actual}) exceeds the maximum allowed by the license key ({limit}); \
consider removing some nodes or acquiring a new license key with a higher limit"
)]
CpuLimitExceeded { limit: u64, actual: u64 },
#[error(
"a valid license key is set, but it is currently not effective because the memory in the cluster \
({actual}) exceeds the maximum allowed by the license key ({limit}); \
consider removing some nodes or acquiring a new license key with a higher limit",
actual = humansize::format_size(*actual, humansize::BINARY),
limit = humansize::format_size(*limit, humansize::BINARY),
)]
MemoryLimitExceeded { limit: u64, actual: u64 },
}View on GitHub (pinned to 6469eb736d)
Solutions
- Re-copy the license key exactly as issued, without surrounding whitespace or quotes, and set it again via the `license_key` system parameter or config.
- Check the `source` chain in the error log (jsonwebtoken::errors::Error) — if it is ExpiredSignature, obtain a renewed license key from RisingWave.
- If using a `test.risingwave.com`-issued key, run a debug build of RisingWave; release builds only accept the `prod` issuer.
- If no valid key is available, unset the key (empty value) to fall back to the default free license, then fix the key later.
Example fix
// before (invalid/truncated key) SET GLOBAL license_key = 'eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIi...truncated'; // after (full, exact key) SET GLOBAL license_key = 'eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.<full-payload>.<full-signature>';
Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate the key before setting it
fn license_key_is_valid(key: &str) -> bool {
if key.is_empty() { return true; } // empty means default license
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
let key = DecodingKey::from_rsa_pem(include_bytes!("key.pub")).unwrap();
let mut v = Validation::new(Algorithm::RS512);
v.set_issuer(&["prod.risingwave.com"]);
decode(key_bytes, &key, &v).is_ok()
} Type guard
fn is_license_error(e: &LicenseError) -> Option<&jsonwebtoken::errors::Error> {
match e { LicenseError::InvalidKey(src) => Some(src), _ => None }
} Try / catch
// Rust has no try/catch; match on the Result
match LicenseManager::get().license() {
Ok(license) => use_license(license),
Err(e @ LicenseError::InvalidKey(_)) => {
tracing::warn!(error = %e.as_report(), "license invalid; falling back to free tier");
fallback_to_default_license();
}
Err(e) => return Err(e.into()),
} Prevention
- Paste license keys programmatically (config management) instead of manual copy-paste to avoid truncation/whitespace.
- Track license expiry and renew before the `exp` claim passes.
- Use prod-issued keys in release builds; test-issuer keys only in debug builds.
- Call Feature::check_available instead of caching the License result, since licenses can expire.
When it happens
Trigger: Calling LicenseManager::refresh(LicenseKey) with a key that is not a valid RS512 JWT signed by RisingWave's key (issuer prod.risingwave.com, or test.risingwave.com in debug builds), a key whose `exp` claim has passed when license() is later called, a corrupted/truncated key string, or a non-empty but garbage value in the license key config (system parameter `license_key`).
Common situations: Typo or truncation when copy-pasting the license key into config; an expired license that was valid at set-time; a test-issuer key used in a release (non-debug) build; whitespace/newlines introduced by shell quoting or YAML; upgrading from a key format the current binary no longer accepts.
Related errors
- argument `--license-key-path` (or env var `RW_LICENSE_KEY_PA
- should have meta client
- Root directory does not exist: {}
- require SQL meta store
- failed to build iceberg compaction execution config
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/5000199d513ebcfe.
Report an issue: GitHub.