nautechsystems/nautilus_trader · error

Payload deployment or retired keys require an active payload

Error message

Payload deployment or retired keys require an active payload sealing key

What it means

PayloadSealingKeys::load returns Ok(None) (no sealing) only when there is no active key env AND no retired keys AND no deployment ID. If an active key env name is absent but retired key envs or a deployment_id are supplied, the configuration is inconsistent and this error is thrown — sealing features are configured without the required active key.

Source

Thrown at crates/adapters/blockchain/src/execution/sealing.rs:86

impl Debug for PayloadKeySet {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct(stringify!(PayloadKeySet))
            .field("active_id", &hex::encode(self.active_id))
            .field("key_count", &self.keys.len())
            .field("deployment_id", &self.deployment_id)
            .finish()
    }
}

impl PayloadKeySet {
    pub(crate) fn load(
        active_env: Option<&str>,
        retired_envs: &[String],
        deployment_id: Option<&str>,
    ) -> anyhow::Result<Option<Self>> {
        let Some(active_env) = active_env else {
            anyhow::ensure!(
                retired_envs.is_empty() && deployment_id.is_none(),
                "Payload deployment or retired keys require an active payload sealing key"
            );
            return Ok(None);
        };
        anyhow::ensure!(
            !active_env.trim().is_empty(),
            "Payload key environment name is empty"
        );
        let deployment_id = deployment_id
            .map(str::trim)
            .filter(|value| !value.is_empty())
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "Payload deployment ID is required when payload sealing is configured"
                )
            })?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set the active payload sealing key env var name in config so active_env is Some.
  2. Or, if sealing is intentionally disabled, remove the retired key env list and payload deployment ID from config.
  3. During key rotation, keep the new active key configured before moving old keys into retired_envs.
  4. Validate sealing config completeness at startup before calling load.

Example fix

// before
retired_envs = ["PAYLOAD_KEY_OLD"]
deployment_id = "dep-123"
# active key env missing

// after
active_env = "PAYLOAD_KEY_NEW"
retired_envs = ["PAYLOAD_KEY_OLD"]
deployment_id = "dep-123"
Defensive patterns

Strategy: validation

Validate before calling

if active_env.is_none() && (!retired_envs.is_empty() || deployment_id.is_some()) {
    panic!("sealing extras configured without an active payload sealing key env");
}

Type guard

fn sealing_config_consistent(active: Option<&str>, retired: &[String], dep: Option<&str>) -> bool { active.is_some() || (retired.is_empty() && dep.is_none()) }

Try / catch

match PayloadSealingKeys::load(active, &retired, dep) {
    Err(e) if e.to_string().contains("require an active payload sealing key") => eprintln!("set the active key env or drop retired/deployment settings"),
    other => other,
}

Prevention

When it happens

Trigger: Calling load with active_env = None while retired_envs is non-empty or deployment_id is Some — e.g. config lists retired payload key env vars or a payload deployment ID but omits the active payload sealing key env.

Common situations: Rotating keys: operator set the retired-key list/deployment ID but forgot to define the new active key env var; config template with commented-out active key line while keeping the rest; partially removed sealing config.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/0183326433185158. Report an issue: GitHub.