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
- Check permissions on the existing PROFILE.md (chmod/chown or delete it so the tool recreates it)
- Free disk space and retry — note a summarize:true retry re-invokes the LLM; prefer summarize:false if the summary was already produced
- Exclude the workspace from AV/sync locks or close editors holding the file
- 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
- Don't make PROFILE.md read-only or lock it in an editor/sync client while the agent writes it
- Watch disk space — the dir create succeeds on a full disk but the write fails
- A failed write loses the (possibly LLM-summarised) body — keep the source markdown until success is confirmed
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
- learning_save_profile: create dir failed: {e}
- artifact_list: {e}
- artifact_get: {e}
- learning_update_facet: {e:#}
- learning_update_facet: upsert failed: {e:#}
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/ed2aeccdd2168873.
Report an issue: GitHub.