facebook/flow · error

max_workers should be positive

Error message

max_workers should be positive

What it means

Standalone server startup converts options.max_workers (an i32 flowing from the CLI --max-workers flag or [server] max_workers in .flowconfig) to NonZeroUsize and expects success (rust_port/crates/flow_server/src/standalone.rs:67-71). A value of 0, or a negative value that wraps when cast to usize, makes NonZeroUsize::new return None and the server panics with 'max_workers should be positive' during startup. It is a configuration validation gate expressed as a panic.

Source

Thrown at rust_port/crates/flow_server/src/standalone.rs:70

use flow_utils_concurrency::thread_pool::ThreadPool;
use flow_utils_concurrency::worker_cancel;

const SERVER_THREAD_STACK_SIZE: usize = if cfg!(windows) {
    64 * 1024 * 1024
} else {
    32 * 1024 * 1024
};
const CONNECTION_THREAD_STACK_SIZE: usize = 2 * 1024 * 1024;
const MAX_CONNECTION_THREADS: usize = 128;
const INITIAL_CONNECTION_READ_TIMEOUT_SECS: u64 = 5;

pub fn start(options: Arc<Options>, flowconfig_name: String) {
    crate::server::check_supported_operating_system(&options);
    flow_server_env::monitor_rpc::disable();
    let committed_heap = Arc::new(CommittedHeap::new());
    let pool = ThreadPool::with_thread_count(ThreadCount::NumThreads(
        std::num::NonZeroUsize::new(options.max_workers as usize)
            .expect("max_workers should be positive"),
    ));
    let tmp_dir = options.temp_dir.to_string();
    let server = FlowServer::new(options, committed_heap, pool, flowconfig_name, tmp_dir);
    server.run();
}

struct ServerState {
    env: Option<flow_server_env::server_env::EnvRef>,
    init_done: bool,
    pending_recheck: bool,
    recheck_in_progress: bool,
    should_shutdown: bool,
}

fn current_persistent_status(
    server_state: &ServerState,
) -> (server_status::Status, file_watcher_status::Status) {
    let status = if !server_state.init_done {

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Set a positive worker count: --max-workers N or server.max_workers = N (>= 1) in .flowconfig, or omit the setting to use the physical-core default
  2. Fix scripts that derive the value arithmetically so they clamp to at least 1
  3. If constructing Options programmatically, assert max_workers >= 1 before calling standalone::start
  4. Upstream: replace the expect with a clear config error that includes the offending value

Example fix

# before (.flowconfig)
[server]
max_workers = 0

# after: positive value, or remove the key entirely
[server]
max_workers = 4

// programmatic guard before start()
assert!(options.max_workers >= 1, "max_workers must be positive, got {}", options.max_workers);
Defensive patterns

Strategy: validation

Validate before calling

// Validate before start()
if options.max_workers < 1 {
    return Err(format!("server.max_workers must be >= 1, got {}", options.max_workers));
}
flow_server::standalone::start(options, flowconfig_name);

Type guard

fn valid_max_workers(n: i32) -> bool {
    n >= 1
}

Prevention

When it happens

Trigger: Passing --max-workers 0; setting server.max_workers = 0 (or a negative value, including the max_workers_full_check variant) in .flowconfig; programmatically building flow_common Options with max_workers left at a 0 default (several internal constructors default it to 0) and calling standalone::start.

Common situations: CI scripts computing worker counts arithmetically (cores - 1 on a 1-core runner yields 0); copy-pasted .flowconfig using max_workers = 0 intending 'auto'; embedding code that constructs Options without the CLI parser.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/60a59fd50088ba52. Report an issue: GitHub.