clockworklabs/SpacetimeDB · error · anyhow::Error
Permission denied for domains: {domains:?}
Error message
Permission denied for domains: {domains:?} What it means
Multi-domain variant of the rename permission failure: the server returned `PermissionDeniedOnAny { domains }` — of the requested domain(s), at least one is not permitted for the authenticated identity. The CLI formats the whole offending list into the error. It comes from the same `PUT /v1/database/{identity}/names` endpoint used by `spacetime rename`.
Source
Thrown at crates/cli/src/subcommands/dns.rs:55
let builder = reqwest::Client::new()
.put(format!(
"{}/v1/database/{database_identity}/names",
config.get_host_url(server)?
))
.header(reqwest::header::CONTENT_TYPE, "application/json")
.body(serde_json::to_string(&[&domain])?);
let builder = add_auth_header_opt(builder, &auth_header);
let response = builder.send().await?;
let status = &response.status();
let result: SetDomainsResult = response.json_or_error().await?;
if !status.is_success() {
anyhow::bail!(match result {
SetDomainsResult::Success => "".to_string(),
SetDomainsResult::PermissionDenied { domain } => format!("Permission denied for domain: {domain}"),
SetDomainsResult::PermissionDeniedOnAny { domains } =>
format!("Permission denied for domains: {domains:?}"),
SetDomainsResult::DatabaseNotFound => format!("Database {database_identity} not found"),
SetDomainsResult::NotYourDatabase { .. } =>
format!("You cannot rename {database_identity} because it is owned by another identity."),
SetDomainsResult::OtherError(err) => err,
});
}
println!("Name set to {domain} for identity {database_identity}.");
Ok(())
}
View on GitHub (pinned to 524b4487d9)
Solutions
- Read the `domains` list in the message and drop or replace each denied name
- Retry with only domains you own, one at a time, to isolate the offender
- Verify the authenticated identity matches the domain owner (`spacetime identity show`)
Defensive patterns
Strategy: try-catch
Validate before calling
// If driving the HTTP API directly, validate ownership per domain first
for d in domains { if !owned(&client, &d)? { return Err(format!("not owned: {d}")); } } Type guard
fn is_denied(msg: &str) -> bool { msg.starts_with("Permission denied for domains:") } Try / catch
// Parse the domains list out of the error, retry the request with only the permitted subset, and report the excluded names to the operator.
Prevention
- Batch only domains under one ownership boundary
- Confirm ownership with the operator's policy before requesting reserved names
When it happens
Trigger: The request body carries a list of domains (the CLI sends one, but the endpoint/API accepts several) and any element is owned/reserved by another party; typically surfaces with multi-name tooling built on the same HTTP API rather than the bare CLI.
Common situations: Custom scripts calling the names endpoint with several candidate domains; partial ownership where you control some names but not others in the list.
Related errors
- Permission denied for domain: {domain}
- Database {database_identity} not found
- You cannot rename {database_identity} because it is owned by
- Failed to read directory {}: {}
- Unsupported --dotnet-version {version}. Supported values: 8,
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/c4a42bfd23917e6d.
Report an issue: GitHub.