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

  1. 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.
  2. Check the `source` chain in the error log (jsonwebtoken::errors::Error) — if it is ExpiredSignature, obtain a renewed license key from RisingWave.
  3. If using a `test.risingwave.com`-issued key, run a debug build of RisingWave; release builds only accept the `prod` issuer.
  4. 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

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


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/5000199d513ebcfe. Report an issue: GitHub.