nautechsystems/nautilus_trader · error

Lighter execution client cannot submit without credentials

Error message

Lighter execution client cannot submit without credentials

What it means

submit_order requires a Lighter credential (API key material used for signing transactions). If self.credential is None the client cannot sign or submit, so it returns this error instead of attempting an unsigned submission. It is a guard against submitting orders with an execution client configured without trading credentials.

Source

Thrown at crates/adapters/lighter/src/execution.rs:4210

        }

        log::info!(
            "Disconnecting Lighter execution client {}",
            self.core.client_id
        );

        self.begin_session_shutdown();
        let tasks_result = self.finish_session_shutdown().await;

        self.core.set_disconnected();

        log::info!("Disconnected: client_id={}", self.core.client_id);
        tasks_result
    }

    fn submit_order(&self, cmd: SubmitOrder) -> anyhow::Result<()> {
        let credential = self.credential.as_ref().ok_or_else(|| {
            anyhow::anyhow!("Lighter execution client cannot submit without credentials")
        })?;

        let order = self.core.cache().try_order_owned(&cmd.client_order_id)?;

        if order.is_closed() {
            log::warn!("Cannot submit closed order {}", order.client_order_id());
            return Ok(());
        }

        let cached_instrument = self
            .core
            .cache()
            .instrument(&order.instrument_id())
            .cloned();

        if let Some(reason) = local_submit_denial_reason(&order, cached_instrument.as_ref()) {
            self.emitter.emit_order_denied(&order, &reason);
            return Ok(());

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Configure the Lighter credentials (api key / private key / account_index / api_key_index) in the execution client config before submitting
  2. Verify env vars or config file are actually read and passed into the client constructor
  3. Use a dedicated trading client instance with credentials instead of the data-only client

Example fix

// before
let client = LighterExecutionClient::new(config_without_credential);
client.submit_order(cmd)?;
// after
let client = LighterExecutionClient::new(config.with_credential(api_key, private_key));
client.submit_order(cmd)?;
Defensive patterns

Strategy: validation

Validate before calling

if client.credential().is_none() {
    return Err(anyhow!("configure Lighter credentials before submitting orders"));
}

Type guard

fn has_credential(c: &LighterExecutionClient) -> bool {
    c.credential().is_some()
}

Try / catch

match client.submit_order(cmd) {
    Err(e) if e.to_string().contains("cannot submit without credentials") => {
        // load credentials and retry or reject order
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling submit_order on a LighterExecutionClient constructed without credentials — e.g. read-only/market-data setup, or credentials failed to load at startup.

Common situations: Config omitting lighter_api_key/private_key or similar env vars; credentials provided to a different client instance; intentionally unauthenticated client used for trading.

Related errors


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