astrid-runtime/astrid · error

failed to persist {}: {e}

Error message

failed to persist {}: {e}

What it means

write_meta serializes meta.json to a temp file in the target directory and then atomically persists it over the final meta.json path. If tempfile's persist (rename) fails — cross-filesystem target, permission problem, or the destination being locked/removed — this error wraps the OS message with the full path.

Source

Thrown at crates/astrid-capsule-install/src/meta.rs:113

            );
            None
        },
    }
}

/// Write `meta.json` to the capsule's install directory.
///
/// Uses atomic write (temp file + rename) to avoid corruption from
/// crashes or power loss during write.
pub fn write_meta(target_dir: &Path, meta: &CapsuleMeta) -> anyhow::Result<()> {
    let meta_path = target_dir.join("meta.json");
    let json = serde_json::to_string_pretty(meta).context("failed to serialize meta.json")?;
    let mut tmp = tempfile::NamedTempFile::new_in(target_dir)
        .context("failed to create temp file for meta.json")?;
    std::io::Write::write_all(&mut tmp, json.as_bytes())
        .context("failed to write meta.json staging")?;
    tmp.persist(&meta_path)
        .map_err(|e| anyhow::anyhow!("failed to persist {}: {e}", meta_path.display()))?;
    Ok(())
}

/// Where an installed capsule lives.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CapsuleLocation {
    /// User-level: `~/.astrid/capsules/`
    User,
    /// Workspace-level: capsules under the selected project state directory.
    Workspace,
}

impl fmt::Display for CapsuleLocation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::User => f.write_str("user"),
            Self::Workspace => f.write_str("workspace"),
        }

View on GitHub (pinned to affd8760f4)

Solutions

  1. Check the wrapped OS error: fix permissions (chmod/chown) on the capsule target directory so the process can write meta.json.
  2. Verify the target directory and temp staging live on the same filesystem (persist is a rename).
  3. Free disk space if the filesystem is full.
  4. Retry the install; if the destination is locked by another process, close it or run when no other capsule operation is active.

Example fix

// before
// running install as user without write access to ~/.astrid/capsules/foo
sudo ./capsule install ./foo
// after
sudo chown -R "$USER" ~/.astrid/capsules/foo
./capsule install ./foo
Defensive patterns

Strategy: try-catch

Validate before calling

// before install
dir.parent().ok_or("no parent")?;
let probe = dir.join(".write-test");
std::fs::write(&probe, b"").map_err(|e| format!("target not writable: {e}"))?;
std::fs::remove_file(&probe)?;

Try / catch

match install_from_local_path(&path) {
    Err(e) if e.to_string().contains("failed to persist") => {
        eprintln!("meta.json persist failed: {e:#}; check permissions/df");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling write_meta (directly or via install_from_local_path_internal or the remove-capsule dependency-validation path) when the staging temp file cannot be renamed onto meta_path: target dir on a different mount, read-only filesystem, or insufficient write permission on the destination.

Common situations: Installing into a capsule directory owned by another user or a read-only mount; disk full; antivirus/indexers holding the destination file on some platforms; target directory deleted between staging and persist.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/b4a1b8026805b321. Report an issue: GitHub.