clockworklabs/SpacetimeDB · error · anyhow::Error

database is a required field in publish config

Error message

database is a required field in publish config

What it means

While preparing dev mode, the CLI maps every publish config to its `database` field in order to stream logs and pick a database for the client process (`db_names_for_logging[0]`). If any entry in `publish_configs` lacks a `database` string, the `.ok_or_else` fires and the whole `collect::<Result<..>>` aborts. Note it indexes `[0]` right after, so an empty publish list would panic rather than error here.

Source

Thrown at crates/cli/src/subcommands/dev.rs:668

        if sc.dev.as_ref().and_then(|d| d.run.as_ref()).is_none() {
            detect_and_save_client_command(&project_dir, Some(sc.clone()))
        } else {
            sc.dev.as_ref().and_then(|d| d.run.clone())
        }
    } else {
        // No config file - try to detect and create new
        detect_and_save_client_command(&project_dir, None)
    };

    // Extract database names from publish configs for log streaming
    let db_names_for_logging: Vec<String> = publish_configs
        .iter()
        .map(|config| {
            config
                .get_config_value("database")
                .and_then(|v| v.as_str())
                .ok_or_else(|| anyhow::anyhow!("database is a required field in publish config"))
                .map(|s| s.to_string())
        })
        .collect::<Result<Vec<_>, _>>()?;

    // Use first database for client process
    let db_name_for_client = &db_names_for_logging[0];

    // Extract watch directories from publish configs
    let watch_dirs = extract_watch_dirs(&publish_configs, &spacetimedb_dir, &project_dir);

    println!("\n{}", "Starting development mode...".green().bold());
    if db_names_for_logging.len() == 1 {
        println!("Database: {}", db_names_for_logging[0].cyan());
    } else {
        println!("Databases: {}", db_names_for_logging.join(", ").cyan());
    }

    // Announce watch directories

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Add `"database": "<name>"` to every publish target in `spacetime.json`
  2. Validate the file: `spacetime json`-lint or `cat spacetime.json | jq .publish` to inspect each target
  3. Ensure the value is a JSON string, not a number or nested object

Example fix

// before
"publish": [{ "module_path": "./spacetimedb" }]
// after
"publish": [{ "module_path": "./spacetimedb", "database": "mydb" }]
Defensive patterns

Strategy: validation

Validate before calling

# Assert every publish target names a database before dev
jq -e '.publish | length > 0 and all(.[]; (.database // "") != "")' spacetime.json \
  || { echo 'publish targets missing "database"'; exit 1; }

Type guard

// In Rust, if building configs programmatically:
fn has_database(t: &serde_json::Value) -> bool {
    t.get("database").and_then(|v| v.as_str()).map_or(false, |s| !s.is_empty())
}

Prevention

When it happens

Trigger: A `spacetime.json` publish target missing the `database` key, or having it as a non-string JSON value (number, object).

Common situations: Hand-editing spacetime.json and forgetting `database`; migrating schema where the field was renamed; copy-pasting a partial target from docs; using `${DB}`-style placeholders that never got substituted.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/6bdedb515e60b27a. Report an issue: GitHub.