clockworklabs/SpacetimeDB · error
Cannot read environment schema: HTTP
Error message
Cannot read environment schema: HTTP {} What it means
Before publishing environment values, `publish_only` GETs `{url}/environment` to fetch the server's declared environment metadata. If the response status is not a success, `ensure!` fails with this message. The request is made with redirects disabled, so redirect statuses (3xx) also trigger this error.
Solutions
- Check the printed HTTP status: 401/403 → re-run `spacetime login`; 404 → verify server version supports environment publication.
- Use the exact `https://` URL for the server to avoid 3xx redirects (redirects are disabled on purpose).
- Confirm the server is reachable and the URL is the API base, not a dashboard page.
- Inspect server logs to see why `/environment` rejected the request.
Example fix
// before spacetime publish -s http://prod.example mydb # redirect -> Cannot read environment schema: HTTP 301 // after spacetime publish -s https://prod.example mydb
Defensive patterns
Strategy: validation
Validate before calling
// pre-flight: reach /environment with auth before the real publish
code=$(curl -s -o /dev/null -w '%{http_code}' -H "Authorization: Bearer $TOKEN" "$SERVER/environment")
[[ "$code" =~ ^2 ]] || { echo "/environment returned $code"; exit 1; } Try / catch
// handle by status class
let e = err.to_string();
if e.contains("401") || e.contains("403") { relogin().await?; }
else if e.contains("30") || e.contains("404") { fix_server_url_or_version()?; } Prevention
- Use exact https:// API base URLs — redirects are intentionally disabled.
- Refresh login tokens before publishing to remote servers.
- Verify the server version supports the environment API before relying on it.
When it happens
Trigger: The `/environment` endpoint returns 401/403 (missing or expired auth), 404 (server doesn't support the environment API / wrong URL), or 3xx (server redirects HTTP→HTTPS or to another host, and the client has `Policy::none`).
Common situations: Stale login token on a remote server; pointing at an old server version without the environment feature; using an `http://` URL where the server redirects to `https://`.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Environment publish failed with HTTP
- Environment read failed with HTTP
- Publish failed with HTTP
- {e}
- Environment key count exceeds limit
AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-09-20).
Data as JSON: /api/errors/0d0d8ebeac95fa90.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/subcommands/publish/environment.rs:117
y_or_n(yes.publish_to_remote, "Are you sure you want to proceed?")?,
"Publish aborted by user"
);
}
let auth = get_auth_header(config, anonymous, server, !yes.skip_login).await?;
let encoded = percent_encoding::percent_encode(
database.as_bytes(),
const { &percent_encoding::NON_ALPHANUMERIC.remove(b'_').remove(b'-') },
)
.to_string();
let url = format!("{host}/v1/database/{encoded}");
// Neither credentials nor publish bodies may be forwarded to redirect destinations.
let client = reqwest::Client::builder()
.redirect(reqwest::redirect::Policy::none())
.build()?;
let response = add_auth_header_opt(client.get(format!("{url}/environment")), &auth)
.send()
.await?;
anyhow::ensure!(
response.status().is_success(),
"Cannot read environment schema: HTTP {}",
response.status()
);
let metadata: EnvironmentMetadata = response.json().await.context("Invalid environment metadata")?;
let schema = EnvironmentSchema::new(metadata.declarations)?;
let resolved = resolve(&schema, input, |key| std::env::var_os(key))?;
options.validate_values(&resolved.values)?;
print!("{}", resolved.display());
let request = PublishRequest {
module: None,
environment: resolved.values,
environment_remove: options.remove.clone(),
environment_replace: options.replace,
expected_module_version: Some(metadata.module_version),
};
let response = add_auth_header_opt(client.put(url), &auth)
.header(reqwest::header::CONTENT_TYPE, CONTENT_TYPE)View on GitHub (pinned to eddf9f5014)