clockworklabs/SpacetimeDB · error
Invalid configuration structure
Error message
Invalid configuration structure
What it means
`decode_config` re-serializes the parsed JSON Value and deserializes it into `SpacetimeConfig`. If serialization of the Value itself fails (a degenerate/invalid Value), the error is this opaque message, again avoiding echoing config contents that may hold secrets.
Solutions
- Replace NaN/Infinity or other non-JSON values in the config with valid JSON numbers or strings.
- Simplify the config structure to plain JSON-compatible objects, arrays, strings, numbers, booleans.
- Update the CLI if this occurs with an apparently normal config, and report it as a bug.
Example fix
// before (config) RATIO: NaN // after (config) RATIO: 0
Defensive patterns
Strategy: validation
Validate before calling
fn is_json_encodable(v: &serde_json::Value) -> bool { !matches!(v, serde_json::Value::Number(n) if n.as_f64().map_or(false, |f| f.is_nan() || f.is_infinite())) } Try / catch
match result { Err(e) if e.to_string() == "Invalid configuration structure" => { eprintln!("Config Value is not JSON-encodable; remove NaN/Infinity or exotic values"); }, Err(e) => return Err(e), Ok(v) => v } Prevention
- Avoid NaN/Infinity and other non-JSON values in config files.
- Keep config structure to plain JSON-compatible types.
- Report reproducible failures on normal configs as CLI bugs.
When it happens
Trigger: A parsed Value that `serde_json::to_vec` cannot encode (e.g. non-string map keys or NaN/floating values not representable in JSON), passed through the environment config decode path.
Common situations: Config files with JSON5 extensions that produce Values outside strict JSON; exotic numeric inputs like NaN or Infinity at the top level of the config.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- database is a required field in publish config
- Environment key : config input must be a string, boolean or…
- unknown field
- cannot replace without enclosing directory
- Database ' ' is not in the config file. If you want to run…
AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-09-20).
Data as JSON: /api/errors/3c2f92dfefeeaffa.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/spacetime_config/environment.rs:100
for (index, (start, end)) in replacements.into_iter().enumerate() {
text.push_str(&content[previous..start]);
text.push_str(&format!("\"{prefix}{index}\""));
previous = end;
}
text.push_str(&content[previous..]);
// Parser diagnostics may quote the source line, which can contain secrets.
let mut value: Value = json5::from_str(&text).map_err(|_| anyhow::anyhow!("Invalid JSON5 configuration"))?;
restore(&mut value, &prefix, &numbers, None)?;
Ok(value)
}
/// Deserialize through JSON text so Serde's flattened-field buffer does not
/// receive visit_u128 from Value's deserializer. That buffer cannot represent
/// u128, while the arbitrary-precision JSON parser preserves its decimal token.
/// Diagnostics discard values while retaining a bounded, ordinary unknown field
/// name, which is useful for correcting misspelled configuration options.
pub(super) fn decode_config(value: Value) -> anyhow::Result<super::SpacetimeConfig> {
let encoded = serde_json::to_vec(&value).map_err(|_| anyhow::anyhow!("Invalid configuration structure"))?;
serde_json::from_slice(&encoded).map_err(|error| {
let diagnostic = error.to_string();
if let Some((field, suffix)) = diagnostic
.strip_prefix("unknown field `")
.and_then(|message| message.split_once('`'))
&& suffix.starts_with(", expected ")
&& !field.is_empty()
&& field.len() <= 64
&& field
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-'))
{
return anyhow::anyhow!("unknown field `{field}`");
}
anyhow::anyhow!("Invalid configuration structure")
})
}
View on GitHub (pinned to eddf9f5014)