clockworklabs/SpacetimeDB · error

Port {} is already in use. Please free up the port or specif

Error message

Port {} is already in use. Please free up the port or specify a different port with --listen-addr.

What it means

spacetime start checks the requested port on both IPv4 and IPv6 before binding. If the port is taken and the process runs in non-interactive mode, it cannot prompt for an alternative and bails immediately with this message.

Source

Thrown at crates/standalone/src/subcommands/start.rs:222

    worker_metrics::spawn_page_pool_stats(listen_addr.clone(), ctx.page_pool().clone());
    worker_metrics::spawn_bsatn_rlb_pool_stats(listen_addr.clone(), ctx.bsatn_rlb_pool().clone());
    let mut db_routes = DatabaseRoutes::default();
    db_routes.root_post = db_routes.root_post.layer(DefaultBodyLimit::disable());
    db_routes.db_put = db_routes.db_put.layer(DefaultBodyLimit::disable());
    db_routes.pre_publish = db_routes.pre_publish.layer(DefaultBodyLimit::disable());
    let extra = axum::Router::new().nest("/health", spacetimedb_client_api::routes::health::router());
    let task_dumps = TaskDumpRegistry::new([("main", main_rt)]);
    let service = router(&ctx, db_routes, IdentityRoutes::default(), extra)
        .layer(Extension(task_dumps))
        .with_state(ctx.clone());

    // Check if the requested port is available on both IPv4 and IPv6.
    // If not, offer to find an available port by incrementing (unless non-interactive).
    let listen_addr = if let Some((host, port_str)) = listen_addr.rsplit_once(':') {
        if let Ok(requested_port) = port_str.parse::<u16>() {
            if !is_port_available(host, requested_port) {
                if non_interactive {
                    anyhow::bail!(
                        "Port {} is already in use. Please free up the port or specify a different port with --listen-addr.",
                        requested_port
                    );
                }
                // Port is in use, try to find an alternative
                match find_available_port(host, requested_port.saturating_add(1), 100) {
                    Some(available_port) => {
                        let question = format!(
                            "Port {} is already in use. Would you like to use port {} instead?",
                            requested_port, available_port
                        );
                        if prompt_yes_no(&question) {
                            format!("{}:{}", host, available_port)
                        } else {
                            anyhow::bail!(
                                "Port {} is already in use. Please free up the port or specify a different port with --listen-addr.",
                                requested_port
                            );

View on GitHub (pinned to 9e0d92412f)

Solutions

  1. Free the port: find and stop the occupying process (lsof -i :<port> then kill, or stop the other spacetimedb instance).
  2. Start on a different port: spacetime start --listen-addr 127.0.0.1:3001.
  3. Run interactively so the server can offer to use a nearby free port.

Example fix

# before
spacetime start --listen-addr 127.0.0.1:3000 # port busy, non-interactive -> bail

# after
lsof -ti :3000 | xargs kill
spacetime start --listen-addr 127.0.0.1:3000
# or: spacetime start --listen-addr 127.0.0.1:3001
Defensive patterns

Strategy: validation

Validate before calling

# probe the port before starting (checks availability):
nc -z 127.0.0.1 3000 && echo "busy -> pick another or free it" || echo "free"
# or: python3 -c "import socket; socket.bind(('127.0.0.1',3000))" && echo free

Try / catch

match start_server(&args).await {
    Err(e) if e.to_string().contains("already in use") => {
        // free the port (kill holder) or retry with --listen-addr on a new port
    }
    other => other,
}

Prevention

When it happens

Trigger: Starting the standalone server with --listen-addr on a port already bound by another process while non-interactive mode is active (no TTY or non-interactive flag), so is_port_available(host, port) returns false.

Common situations: A previous spacetime start still running in another terminal or as a background service; CI containers with an already-mapped port; another application (Postgres, node) occupying the default port.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@9e0d92412f (2026-08-20). Data as JSON: /api/errors/e38671d1304a285a. Report an issue: GitHub.