screenpipe/screenpipe · error

Failed to write file {}: {}

Error message

Failed to write file {}: {}

What it means

This error wraps an I/O failure from tokio::fs::write while persisting a downloaded file from an MCP directory archive to its target path on disk. The anyhow context adds the destination path and the underlying std::io::Error so you can see both where the write failed and why (permissions, disk full, missing parent dir, etc.).

Source

Thrown at crates/screenpipe-engine/src/cli/mcp.rs:265

        .map_err(|e| anyhow::anyhow!("Failed to parse GitHub API response: {}", e))?;

    for item in contents {
        let target_path = target_dir.join(&item.name);

        match item.content_type.as_str() {
            "file" => {
                if let Some(download_url) = item.download_url {
                    let file_response = client.get(&download_url).send().await.map_err(|e| {
                        anyhow::anyhow!("Failed to download file {}: {}", download_url, e)
                    })?;

                    let content = file_response
                        .bytes()
                        .await
                        .map_err(|e| anyhow::anyhow!("Failed to get file content: {}", e))?;

                    tokio::fs::write(&target_path, content).await.map_err(|e| {
                        anyhow::anyhow!("Failed to write file {}: {}", target_path.display(), e)
                    })?;

                    debug!("Downloaded file: {}", target_path.display());
                }
            }
            "dir" => {
                tokio::fs::create_dir_all(&target_path).await.map_err(|e| {
                    anyhow::anyhow!(
                        "Failed to create directory {}: {}",
                        target_path.display(),
                        e
                    )
                })?;

                let subdir_api_url = format!(
                    "https://api.github.com/repos/{}/{}/contents/{}?ref={}",
                    "screenpipe", "screenpipe", item.path, "main"
                );

View on GitHub (pinned to 4ebf712990)

Solutions

  1. Read the wrapped io::Error kind in the message and fix the underlying cause (permissions, disk space, path type).
  2. Ensure the parent directory exists before writing (create_dir_all on target_path's parent).
  3. Check that target_path is not an existing directory; remove or pick a different target.
  4. Retry the download if it was a transient lock (AV scanner, cloud-sync placeholder).

Example fix

// before
tokio::fs::write(&target_path, content).await.map_err(|e| {
    anyhow::anyhow!("Failed to write file {}: {}", target_path.display(), e)
})?;
// after
if let Some(parent) = target_path.parent() {
    tokio::fs::create_dir_all(parent).await?;
}
tokio::fs::write(&target_path, content).await.map_err(|e| {
    anyhow::anyhow!("Failed to write file {}: {}", target_path.display(), e)
})?;
Defensive patterns

Strategy: try-catch

Validate before calling

// before download
if let Some(parent) = std::path::Path::new(&target_path).parent() {
    tokio::fs::create_dir_all(parent).await?;
}

Try / catch

match tokio::fs::write(&target_path, content).await {
    Ok(_) => {},
    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => eprintln!("no write permission at {}", target_path.display()),
    Err(e) => return Err(anyhow::anyhow!("write {} failed: {}", target_path.display(), e)),
}

Prevention

When it happens

Trigger: download_mcp_directory fetched a 'file' entry from the archive listing, downloaded its bytes successfully, but tokio::fs::write(&target_path, content) failed — e.g. the parent directory was not created first, the path is not writable, or the disk is full.

Common situations: Downloading an MCP directory into a location without write permissions (~/Library or C:\Program Files), antivirus/backup software locking the file, or a race where the target path exists as a directory so the write fails with IsADirectory.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01). Data as JSON: /api/errors/342ab5a2494b3a32. Report an issue: GitHub.