unicity-aos/capsule-identity · warning
Failed to parse spark.toml, using defaults
Error message
Failed to parse spark.toml, using defaults: {e} What it means
parse_spark_toml parses spark.toml content into a SparkConfig via toml::from_str. When parsing fails, it logs this warning and falls back to SparkConfig::default() instead of propagating the error, so the caller (handle_command) always receives a valid config. The interpolated `e` carries the underlying serde/TOML error detailing why deserialization failed.
Solutions
- Fix the TOML syntax error at the location given in the parse error `e` inside the logged message.
- Check that all fields conform to SparkConfig's serde types and remove obsolete or mistyped fields.
- Replace the file with SparkConfig::default() output (serialize via toml::to_string) and re-add settings one at a time, re-running to confirm each parses.
- For callers needing the exact problem surfaced, consider changing parse_spark_toml to return Result<SparkConfig, toml::de::Error> rather than silently defaulting, or at least surface the warning in command output.
Example fix
// before: silent fallback
toml::from_str(content).unwrap_or_else(|e| {
log::warn(format!("Failed to parse spark.toml, using defaults: {e}"));
SparkConfig::default()
})
// after: caller can see and handle the failure
match toml::from_str::<SparkConfig>(content) {
Ok(cfg) => cfg,
Err(e) => {
log::warn(format!("Failed to parse spark.toml, using defaults: {e}"));
SparkConfig::default()
}
} Defensive patterns
Strategy: validation
Validate before calling
// Validate before passing content to the parser
fn validate_spark_toml(content: &str) -> Result<SparkConfig, toml::de::Error> {
toml::from_str(content)
}
// caller:
let cfg = validate_spark_toml(&content)?; // or handle Err explicitly Type guard
fn parses_as_spark_config(content: &str) -> bool {
toml::from_str::<SparkConfig>(content).is_ok()
} Try / catch
// Handle the Err branch explicitly instead of trusting the silent default
let config = toml::from_str::<SparkConfig>(content)
.unwrap_or_else(|e| {
log::warn(format!("spark.toml invalid ({e}); defaults in effect"));
SparkConfig::default()
}); Prevention
- Write spark.toml programmatically with toml::to_string from SparkConfig; avoid manual edits.
- Round-trip check (parse immediately after write) whenever the file changes.
- In CI or startup checks, parse the config and fail fast with the detailed serde error message.
- Guard against truncated writes by writing to a temp file and atomically renaming it into place.
When it happens
Trigger: Calling handle_command with a command that routes through parse_spark_toml on spark.toml content that toml::from_str cannot deserialize: invalid TOML syntax, wrong field types relative to SparkConfig, or incompatible/unknown field structure for the current schema.
Common situations: Hand-edited spark.toml with syntax mistakes; config written by an older release whose fields were renamed or retyped; a partially written/corrupted file (e.g. crash mid-write); copy-pasting config with mismatched quotes or indentation in TOML.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of unicity-aos/capsule-identity@1364a437f3 (2026-09-13).
Data as JSON: /api/errors/2eed509fd2bb5673.
Report an issue: GitHub.
Appendix: source
Thrown at src/lib.rs:279
pub fn save_identity(&mut self, args: SparkConfig) -> Result<serde_json::Value, SysError> {
self.spark = args;
self.onboarded = true;
// Persist to spark.toml so identity survives KV resets.
let toml = self.spark.to_toml();
fs::write(SPARK_CONFIG_PATH, toml.as_bytes())?;
Ok(serde_json::json!({
"status": "ok",
"callsign": self.spark.callsign,
}))
}
}
/// Parse spark.toml into a `SparkConfig`.
fn parse_spark_toml(content: &str) -> SparkConfig {
toml::from_str(content).unwrap_or_else(|e| {
log::warn(format!("Failed to parse spark.toml, using defaults: {e}"));
SparkConfig::default()
})
}
#[cfg(test)]
mod tests {
use super::*;
fn configured_identity() -> SparkConfig {
SparkConfig {
callsign: "Lyra".into(),
class: "a precise concierge agent".into(),
aura: "Calm, direct, and context aware.".into(),
signal: "Use short answers unless detail is needed.".into(),
core: "Preserve user boundaries.".into(),
}
}
View on GitHub (pinned to 1364a437f3)