gleam-lang/gleam · error

Unable to start Tokio async runtime

Error message

Unable to start Tokio async runtime

What it means

publish.rs::main creates its Tokio runtime with expect("Unable to start Tokio async runtime") after listing files and asking 'Do you wish to publish this package?'. This is the same resource-exhaustion failure as other commands: the multi-thread runtime cannot spawn workers or register its I/O driver. The panic fires after confirmation but before hex::publish_package, so no package state changes on hex.pm.

Source

Thrown at compiler-cli/src/publish.rs:87

        println!("\nGenerated files:");
        for file in generated_files_added.iter().sorted() {
            println!("  - {}", file.0);
        }
    }
    println!("\nSource files:");
    for file in src_files_added.iter().sorted() {
        println!("  - {file}");
    }
    println!("\nName: {}", config.name);
    println!("Version: {}", config.version);

    let should_publish = i_am_sure || cli::confirm("\nDo you wish to publish this package?")?;
    if !should_publish {
        println!("Not publishing.");
        return Ok(());
    }

    let runtime = tokio::runtime::Runtime::new().expect("Unable to start Tokio async runtime");
    let http = HttpClient::new();
    let hex_config = hexpm::Config::new();
    let credentials = crate::hex::HexAuthentication::new(&runtime, &http, hex_config.clone())
        .get_or_create_api_credentials()?;
    let credentials = crate::hex::write_credentials(&credentials)?;
    cli::print_publishing(&config.name, &config.version);

    runtime.block_on(hex::publish_package(
        package_tarball,
        config.version.to_string(),
        &config.name,
        &credentials,
        &hex_config,
        replace,
        &http,
    ))?;

    cli::print_publishing_documentation();

View on GitHub (pinned to 7e623aa83d)

Solutions

  1. Re-run publish with more headroom: raise the container pids limit and thread ulimits, or exec the publish step outside the sandbox.
  2. Relieve memory/thread pressure on the machine (wait for parallel jobs), then `gleam publish --yes` to skip the interactive prompt.
  3. For library users of this code, replace Runtime::new() with Builder::new_current_thread().enable_all().build().
  4. Confirm the limit in CI logs (`pids.max`, exit context) and bake a higher limit into the release job image.

Example fix

# before: release job constrained by default pids limit
- run: gleam publish --yes   # panics: Unable to start Tokio async runtime

# after: publish step with adequate limits
- run: gleam publish --yes
  # plus container config: pids_limit: 512 (compose) or --pids-limit=512 (docker)
Defensive patterns

Strategy: retry

Validate before calling

# Release pipeline preflight: enough pids and memory for a Tokio runtime
[ "$(cat /sys/fs/cgroup/pids/pids.max 2>/dev/null)" != "16" ] || (echo raise pids limit; exit 1)
avail_kb=$(awk '/MemAvailable/{print $2}' /proc/meminfo); [ "$avail_kb" -gt 262144 ] || exit 1
gleam publish --yes

Prevention

When it happens

Trigger: `gleam publish` in a CI container with low pids-limit, low ulimit -u/-v, heavy memory pressure, or a seccomp/gVisor sandbox blocking the syscalls Tokio needs — hitting exactly between the confirmation prompt and the upload.

Common situations: Release pipelines in Docker (default or small --pids-limit), self-hosted runners shared with many jobs, or gVisor/Firecracker CI sandboxes; the tag was pushed and CI failed at publish time.

Related errors


AI-assisted analysis of gleam-lang/gleam@7e623aa83d (2026-08-17). Data as JSON: /api/errors/65a1930a8a31a82a. Report an issue: GitHub.