clockworklabs/SpacetimeDB · error

Environment values can only be changed by publishing

Error message

Environment values can only be changed by publishing

What it means

The `spacetime env` CLI subcommand only supports read-only operations (`list` and `get`). Any other subcommand (e.g. `set`, `unset`) reaches the catch-all arm and is rejected, because environment values are mutated exclusively through the publish flow.

Solutions

  1. Use `spacetime publish` (with the desired environment values in the config) to change environment values instead of `spacetime env set`.
  2. Check `spacetime env --help` and use only `list` or `get` to read values.
  3. Fix typos in the subcommand verb.

Example fix

// before
spacetime env set MY_KEY myvalue
// after
spacetime publish --project-path . # with MY_KEY set in the environment config
Defensive patterns

Strategy: validation

Validate before calling

if !matches!(verb.as_str(), "list" | "get") { eprintln!("env values are read-only via `spacetime env`; use `spacetime publish` to change them"); std::process::exit(2); }

Type guard

fn is_readonly_env_query(verb: &str) -> bool { matches!(verb, "list" | "get") }

Prevention

When it happens

Trigger: Running `spacetime env set KEY VALUE` (or any verb other than `list`/`get`); typoing a subcommand such as `spacetime env put`.

Common situations: Developers expecting shell-like `env set` semantics after deploying; scripts ported from other tools that mutate env vars in place; typos in the env subcommand name.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at crates/cli/src/subcommands/env.rs:75

            Self::Get(key) => {
                // POSIX names cannot contain quotes or SQL syntax.
                validate_key(key).map_err(|_| anyhow::anyhow!("Invalid environment key name"))?;
                Ok(format!("SELECT value FROM st_env WHERE key = '{key}'"))
            }
        }
    }
}

pub async fn exec(config: Config, args: &ArgMatches) -> anyhow::Result<()> {
    let (command, args) = args.subcommand().context("Expected env get or list")?;
    let query = match command {
        "list" => Query::List,
        "get" => Query::Get(
            args.get_one::<String>("key")
                .context("Expected environment key")?
                .clone(),
        ),
        _ => anyhow::bail!("Environment values can only be changed by publishing"),
    };
    query.sql()?;
    let targets = load_config_db_targets(args.get_flag("no_config"))?;
    let database = resolve_database_arg(
        args.get_one::<String>("database").map(String::as_str),
        targets.as_deref(),
        "spacetime env get/list <database>",
    )?;
    let con = sql::parse_req(config, args, &database.database, database.server.as_deref()).await?;
    let mut request = ClientApi::new(con).sql();
    if let Some(confirmed) = args.get_one::<bool>("confirmed") {
        request = request.query(&[("confirmed", confirmed)]);
    }
    print!("{}", fetch(request, query).await?);
    Ok(())
}

async fn fetch(request: reqwest::RequestBuilder, query: Query) -> anyhow::Result<String> {

View on GitHub (pinned to eddf9f5014)