Zackriya-Solutions/meetily · info

metadata value checked as object

Error message

metadata value checked as object

What it means

serde_json's Value::as_object_mut() returns Some only when the root value is a JSON object. The code checks value.is_object() and bails with a proper error otherwise, so the .expect("metadata value checked as object") is a correctly defended invariant — reachable only if future edits mutate value's variant between the check and the use.

Source

Thrown at frontend/src-tauri/src/summary/metadata.rs:80

    summary_language: Option<&str>,
) -> Result<()> {
    let _guard = METADATA_WRITE_LOCK.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
    let metadata_path = metadata_path(folder);
    let temp_path = metadata_temp_path(folder);

    let mut value = if metadata_path.exists() {
        let raw = std::fs::read_to_string(&metadata_path)
            .with_context(|| format!("Failed to read {}", metadata_path.display()))?;
        parse_metadata_json(&raw)?
    } else {
        Value::Object(serde_json::Map::new())
    };

    if !value.is_object() {
        bail!("Failed to parse metadata.json: root value must be a JSON object");
    }

    let object = value.as_object_mut().expect("metadata value checked as object");
    match summary_language {
        Some(code) => {
            let normalised = normalise_supported_summary_language(code)?;
            object.insert(field.to_string(), Value::String(normalised));
        }
        None => {
            object.remove(field);
        }
    }

    let json_string = serde_json::to_string_pretty(&value)
        .context("Failed to serialize metadata.json")?;
    std::fs::write(&temp_path, json_string)
        .with_context(|| format!("Failed to write {}", temp_path.display()))?;
    std::fs::rename(&temp_path, &metadata_path).with_context(|| {
        format!(
            "Failed to replace {} with {}",
            metadata_path.display(),

View on GitHub (pinned to 0281737d87)

Solutions

  1. None required — the guard is already correct
  2. Optionally make the narrowing explicit with let-else: `let Value::Object(object) = &mut value else { bail!(...) };`
  3. Keep the is_object check directly adjacent to the as_object_mut call in future edits

Example fix

// after (idiomatic narrowing, no expect)
let Value::Object(object) = &mut value else {
    bail!("Failed to parse metadata.json: root value must be a JSON object");
};
Defensive patterns

Strategy: type-guard

Validate before calling

if !value.is_object() {
    anyhow::bail!("metadata.json root must be a JSON object");
}

Type guard

fn is_json_object(v: &serde_json::Value) -> bool {
    v.is_object()
}

Prevention

When it happens

Trigger: Only via a refactor that reassigns `value` (or calls code that can) between the is_object() check and the expect; as written the two lines are adjacent and the panic is unreachable.

Common situations: Never observed; this check-then-expect pairing is the recommended pattern for narrowing serde_json roots without cloning.

Related errors


AI-assisted analysis of Zackriya-Solutions/meetily@0281737d87 (2026-08-16). Data as JSON: /api/errors/e6ff479c99738f45. Report an issue: GitHub.