tinyhumansai/openhuman · error

learning_save_profile: write failed: {e}

Error message

learning_save_profile: write failed: {e}

What it means

Thrown by learning_save_profile when the final tokio::fs::write() of PROFILE.md into workspace_dir fails. The directory was ensured successfully one step earlier, so this is a file-level failure: permission on the file itself, disk full, or the file being held exclusively by another process. Nothing is persisted — the body (possibly an LLM summary you paid for) is lost unless retried.

Source

Thrown at src/openhuman/agent/learning/tools.rs:548

            .map_err(|e| anyhow::anyhow!("learning_save_profile: {e}"))?;
        let body = if summarize {
            crate::openhuman::agent::learning::linkedin_enrichment::summarise_profile_with_llm(
                &config, &markdown,
            )
            .await
            .map_err(|e| anyhow::anyhow!("learning_save_profile: summarisation failed: {e:#}"))?
        } else {
            markdown
        };
        let path = config.workspace_dir.join("PROFILE.md");
        if let Some(parent) = path.parent() {
            tokio::fs::create_dir_all(parent)
                .await
                .map_err(|e| anyhow::anyhow!("learning_save_profile: create dir failed: {e}"))?;
        }
        tokio::fs::write(&path, &body)
            .await
            .map_err(|e| anyhow::anyhow!("learning_save_profile: write failed: {e}"))?;
        Ok(ToolResult::success(serde_json::to_string(&json!({
            "path": path.display().to_string(),
            "bytes": body.len(),
        }))?))
    }
}

/// Enrich the profile via LinkedIn (external scrape). Default-OFF.
pub struct LearningEnrichProfileTool;

#[async_trait]
impl Tool for LearningEnrichProfileTool {
    fn name(&self) -> &str {
        "learning_enrich_profile"
    }

    fn description(&self) -> &str {
        "Run the LinkedIn profile-enrichment pipeline: optionally with a preset \

View on GitHub (pinned to a221052e0d)

Solutions

  1. Check permissions on the existing PROFILE.md (chmod/chown or delete it so the tool recreates it)
  2. Free disk space and retry — note a summarize:true retry re-invokes the LLM; prefer summarize:false if the summary was already produced
  3. Exclude the workspace from AV/sync locks or close editors holding the file
  4. Retry the tool once the blocker is removed
Defensive patterns

Strategy: try-catch

Validate before calling

let path = cfg.workspace_dir.join("PROFILE.md");
if path.exists() {
    let md = std::fs::metadata(&path)?;
    assert!(md.permissions().readonly() == false, "PROFILE.md is read-only — fix before save");
}

Try / catch

match tool_exec("learning_save_profile", args).await {
    Err(e) if e.to_string().contains("write failed") => {
        // check: ENOSPC -> free space; EACCES -> chmod/chown PROFILE.md; success dir exists, so it's file-level
        Err(e)
    }
    other => other,
}

Prevention

When it happens

Trigger: An existing read-only PROFILE.md (checked into a repo, chmod 444); disk filling between the create_dir_all and the write; antivirus/sync clients (Windows OneDrive, AV) holding the file; a text editor with an exclusive lock open.

Common situations: Users keep their workspace in a synced/read-only folder; CI running the core against a constrained sandbox; PROFILE.md owned by root after a sudo run.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/ed2aeccdd2168873. Report an issue: GitHub.