clockworklabs/SpacetimeDB · error
Database environment variables can only be changed by…
Error message
Database environment variables can only be changed by publishing
What it means
SQL DML against the st_env system table is blocked: environment variables for a database are managed exclusively through the publish flow, which validates keys, records the environment schema, and updates program metadata atomically. Direct SQL writes would bypass those invariants, so run_inner rejects them with this error.
Solutions
- Change environment variables by republishing with the desired environment spec (`spacetime publish` with the updated environment).
- Read-only SELECTs on st_env remain allowed — use SELECT to inspect current values.
- For secrets/config not tied to publishing, store them in your own table instead of st_env.
Example fix
-- before: direct DML on env table UPDATE st_env SET value = 'v2' WHERE key = 'API_KEY'; -- after: change via publish (CLI) -- spacetime publish mydb --env API_KEY=v2
Defensive patterns
Strategy: validation
Validate before calling
-- reject st_env DML before sending
if sql.trim().toUpperCase().startsWith(('INSERT','UPDATE','DELETE')) && /\bst_env\b/.test(sql) throw new Error('mutate st_env only via publish'); Try / catch
try { execSql(sql); } catch (e) { if (e.message.includes('can only be changed by publishing')) switchToPublishFlow(); else throw e; } Prevention
- Treat st_env as read-only in SQL
- Manage env via the publish command/API
- Use your own tables for app-managed config
When it happens
Trigger: Executing an SQL INSERT/UPDATE/DELETE statement whose stmt.table_id() == ST_ENV_ID via the SQL execution API, even when the caller has write access.
Common situations: A developer trying to set or tweak a database config variable with `UPDATE st_env SET value=...` in the SQL console; automation scripts mutating env rows directly.
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
- Caller is not authorized to run SQL DML statements
- Invalid environment key name
- Cannot define RLS rule on private table
- Cannot read environment schema: HTTP
- `cmake` not found in PATH.
AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-09-20).
Data as JSON: /api/errors/16659a916da8a723.
Report an issue: GitHub.
Appendix: source
Thrown at crates/core/src/sql/execute.rs:150
// Update transaction metrics
tx.metrics.merge(metrics);
Ok((
SqlResult {
tx_offset,
rows,
metrics: tx.metrics,
},
trapped,
))
}
Statement::DML(stmt) => {
// An extra layer of auth is required for DML
if !auth.has_write_access() {
return Err(anyhow!("Caller {} is not authorized to run SQL DML statements", auth.caller()).into());
}
if stmt.table_id() == spacetimedb_datastore::system_tables::ST_ENV_ID {
return Err(anyhow!("Database environment variables can only be changed by publishing").into());
}
// Evaluate the mutation
let (mut tx, _) = db.with_auto_rollback(tx, |tx| execute_dml_stmt(&auth, stmt, tx, &mut metrics))?;
// Update transaction metrics
tx.metrics.merge(metrics);
// Update views
let (result, _num_views_evaluated, trapped) = match instance {
Some(instance) => ModuleHost::call_views_with_tx(tx, instance, auth.caller()),
None => (ViewCallResult::default(tx), 0, false),
};
// Rollback transaction and report metrics if view execution failed
if let ViewOutcome::Failed(err) = result.outcome {
let (_, metrics, reducer) = db.rollback_mut_tx(result.tx);
db.report_mut_tx_metrics(reducer, metrics, None);View on GitHub (pinned to eddf9f5014)