nautechsystems/nautilus_trader · critical · anyhow::Error

username not set nor available in env TWS_USERNAME

Error message

username not set nor available in env TWS_USERNAME

What it means

DockerizedIBGateway::new requires IB Gateway credentials. It takes username from the DockerizedIBGatewayConfig and falls back to the TWS_USERNAME environment variable; if both are absent it returns this error rather than constructing the gateway manager. Credentials are held as SecretString and are never read later.

Source

Thrown at crates/adapters/interactive_brokers/src/gateway/dockerized.rs:180

    }

    /// Create a new DockerizedIBGateway from configuration.
    ///
    /// # Arguments
    ///
    /// * `config` - Configuration for the gateway
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - Username or password is not provided and not available in environment variables
    /// - Docker client creation fails
    pub fn new(mut config: DockerizedIBGatewayConfig) -> anyhow::Result<Self> {
        let username = config
            .username
            .take()
            .or_else(|| std::env::var("TWS_USERNAME").ok().map(SecretString::from))
            .ok_or_else(|| anyhow::anyhow!("username not set nor available in env TWS_USERNAME"))?;

        let password = config
            .password
            .take()
            .or_else(|| std::env::var("TWS_PASSWORD").ok().map(SecretString::from))
            .ok_or_else(|| anyhow::anyhow!("password not set nor available in env TWS_PASSWORD"))?;

        // Connect to Docker
        let docker = Docker::connect_with_local_defaults().context(
            "Failed to connect to the local Docker daemon. Ensure Docker is running and the local Docker socket is available",
        )?;

        // Determine port based on trading mode
        let mode_str = match config.trading_mode {
            crate::config::TradingMode::Paper => "Paper",
            crate::config::TradingMode::Live => "Live",
        };
        let port = Self::host_port_for_mode(config.trading_mode);

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set TWS_USERNAME in the environment before starting the process (e.g. `export TWS_USERNAME=...` or pass it via Docker/systemd EnvFile).
  2. Set `username` explicitly on DockerizedIBGatewayConfig.
  3. Load credentials from a .env file or secret manager into the process environment at startup.
  4. Verify with a quick check that the env var is visible to the exact process running the gateway.

Example fix

// before
let gateway = DockerizedIBGateway::new(DockerizedIBGatewayConfig::default())?;
// after
let gateway = DockerizedIBGateway::new(DockerizedIBGatewayConfig {
    username: Some(SecretString::from("my_user")),
    ..Default::default()
})?;
Defensive patterns

Strategy: validation

Validate before calling

if std::env::var("TWS_USERNAME").is_err() {
    panic!("TWS_USERNAME must be set (or pass username in DockerizedIBGatewayConfig) before starting the gateway");
}

Try / catch

match DockerizedIBGateway::new(config) {
    Ok(gw) => (),
    Err(e) if e.to_string().contains("username not set nor available in env TWS_USERNAME") => {
        return Err(anyhow!("gateway credentials missing: set TWS_USERNAME or config.username"));
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling DockerizedIBGateway::new with config.username == None while TWS_USERNAME is not set in the process environment.

Common situations: Running the node under systemd/Docker/K8s where the shell profile exporting TWS_USERNAME is not loaded; forgetting the env var in CI; building the config programmatically and omitting the username field.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


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