clockworklabs/SpacetimeDB · error

Too many environment removals

Error message

Too many environment removals

What it means

Thrown by `from_args` in crates/cli/src/subcommands/publish.rs when `spacetime publish` is invoked with more `--unset-env` keys than `spacetimedb_lib::environment::MAX_ENV_VARS`. The removal list is validated before any keys are sent to the server.

Solutions

  1. Reduce the number of `--unset-env` flags to at most MAX_ENV_VARS per publish.
  2. Recreate the environment (publish fresh) instead of unsetting every key individually.
  3. Fix the generating script to deduplicate and cap the removal list.
  4. If wholesale clearing is intended, unset keys across multiple publishes.

Example fix

// before
spacetime publish my-db --unset-env K1 --unset-env K2 ... # 300 flags
// after
spacetime publish my-db --replace-env   # or unset in batches of <= MAX_ENV_VARS
Defensive patterns

Strategy: validation

Validate before calling

// cap removal list before building the publish command
if keys_to_unset.len() > spacetimedb_lib::environment::MAX_ENV_VARS {
    return Err("too many env removals for one publish");
}

Prevention

When it happens

Trigger: A publish command passes a very long list of `--unset-env KEY` flags such that `options.remove.len() > MAX_ENV_VARS` — usually from a generated/scripted command line with hundreds of unset flags.

Common situations: Auto-generated deploy scripts that enumerate every previously-set key for removal; batch migrations clearing large inherited environments; shell expansion mistakes duplicating flags.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-09-20). Data as JSON: /api/errors/36ae4b90a45a3e2d. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/subcommands/publish.rs:372

#[derive(Default)]
struct EnvironmentOptions {
    only: bool,
    remove: Vec<String>,
    replace: bool,
}

impl EnvironmentOptions {
    fn from_args(args: &ArgMatches) -> anyhow::Result<Self> {
        let options = Self {
            only: args.get_flag("env_only"),
            remove: args
                .get_many::<String>("unset_env")
                .map(|keys| keys.cloned().collect())
                .unwrap_or_default(),
            replace: args.get_flag("replace_env"),
        };
        ensure!(
            options.remove.len() <= spacetimedb_lib::environment::MAX_ENV_VARS,
            "Too many environment removals"
        );
        for key in &options.remove {
            spacetimedb_lib::environment::validate_key(key)?;
        }
        Ok(options)
    }

    fn validate_values(&self, values: &std::collections::BTreeMap<String, String>) -> anyhow::Result<()> {
        ensure!(
            !self.replace || self.remove.is_empty(),
            "--replace-env cannot be combined with --unset-env"
        );
        for key in &self.remove {
            ensure!(
                !values.contains_key(key),
                "Environment key {key:?} is both supplied and removed"

View on GitHub (pinned to eddf9f5014)