{"record":{"id":"2529313cc6e1a644","repo":"astrid-runtime/astrid","slug":"gateway-revocation-namespace-exceeds-entry-cap","errorCode":null,"errorMessage":"gateway revocation namespace exceeds entry cap","messagePattern":"gateway revocation namespace exceeds entry cap","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-gateway/src/revocations.rs","lineNumber":310,"sourceCode":"    };\n    Ok(publish_device_epoch(revoked_key_ids, key_id, durable_epoch))\n}\n\n/// Load all durable principal and device epochs from the fixed control\n/// namespace. Every key/value is bounded and validated before publication.\npub async fn load_from_store(\n    store: &dyn KvStore,\n) -> anyhow::Result<(HashMap<PrincipalId, u64>, HashMap<String, u64>)> {\n    let principal_keys = store\n        .list_keys_with_prefix(REVOCATION_NAMESPACE, PRINCIPAL_PREFIX)\n        .await\n        .map_err(|error| anyhow::anyhow!(\"list principal revocations: {error}\"))?;\n    let device_keys = store\n        .list_keys_with_prefix(REVOCATION_NAMESPACE, DEVICE_PREFIX)\n        .await\n        .map_err(|error| anyhow::anyhow!(\"list device revocations: {error}\"))?;\n    if principal_keys.len().saturating_add(device_keys.len()) > MAX_REVOCATION_ENTRIES {\n        anyhow::bail!(\"gateway revocation namespace exceeds entry cap\");\n    }\n    let mut principals = HashMap::with_capacity(principal_keys.len());\n    for key in principal_keys {\n        let alias = key\n            .strip_prefix(PRINCIPAL_PREFIX)\n            .filter(|alias| !alias.is_empty())\n            .ok_or_else(|| anyhow::anyhow!(\"invalid principal revocation key {key:?}\"))?;\n        let principal = PrincipalId::new(alias).map_err(|error| {\n            anyhow::anyhow!(\"invalid principal revocation key {key:?}: {error}\")\n        })?;\n        let value = store\n            .get(REVOCATION_NAMESPACE, &key)\n            .await\n            .map_err(|error| anyhow::anyhow!(\"read principal revocation {key:?}: {error}\"))?\n            .ok_or_else(|| {\n                anyhow::anyhow!(\"principal revocation {key:?} disappeared during load\")\n            })?;\n        principals.insert(principal, decode_epoch(&value, &key)?);","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-gateway/src/revocations.rs#L292-L328","documentation":"Bounds guard in load_from_store: the number of principal/device revocation keys listed from the fixed control namespace exceeded the entry cap, so startup hydration aborts rather than trusting an oversized revocation set.","triggerScenarios":"Thrown at crates/astrid-gateway/src/revocations.rs:310 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Audit the revocation namespace for runaway key growth (e.g. a bug writing unbounded keys)","Prune expired/rotated revocation entries below the cap","Raise the cap only after confirming the growth is legitimate"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}