{"record":{"id":"0cf11bcfd6196a7d","repo":"tinyhumansai/openhuman","slug":"failed-to-atomically-persist-active-workspace-mark","errorCode":null,"errorMessage":"Failed to atomically persist active workspace marker {}: {error}","messagePattern":"Failed to atomically persist active workspace marker (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/config/schema/load/dirs.rs","lineNumber":233,"sourceCode":"        config_dir: config_dir.to_string_lossy().into_owned(),\n    };\n    let serialized =\n        toml::to_string_pretty(&state).context(\"Failed to serialize active workspace marker\")?;\n\n    let temp_path = default_config_dir.join(format!(\n        \".{ACTIVE_WORKSPACE_STATE_FILE}.tmp-{}\",\n        uuid::Uuid::new_v4()\n    ));\n    fs::write(&temp_path, serialized).await.with_context(|| {\n        format!(\n            \"Failed to write temporary active workspace marker: {}\",\n            temp_path.display()\n        )\n    })?;\n\n    if let Err(error) = fs::rename(&temp_path, &state_path).await {\n        let _ = fs::remove_file(&temp_path).await;\n        anyhow::bail!(\n            \"Failed to atomically persist active workspace marker {}: {error}\",\n            state_path.display()\n        );\n    }\n\n    super::sync_directory(&default_config_dir).await?;\n    Ok(())\n}\n\npub(crate) fn resolve_config_dir_for_workspace(workspace_dir: &Path) -> (PathBuf, PathBuf) {\n    let workspace_config_dir = workspace_dir.to_path_buf();\n    if workspace_config_dir.join(\"config.toml\").exists() {\n        return (\n            workspace_config_dir.clone(),\n            workspace_config_dir.join(\"workspace\"),\n        );\n    }\n","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/config/schema/load/dirs.rs#L215-L251","documentation":"The active-workspace marker is persisted atomically: serialize state, write to a UUID-suffixed temp file in the default config dir, then `fs::rename` over the marker path (followed by a directory fsync). This bail fires when the rename step fails — the temp file is removed first, so no half-written marker is left; the previous marker, if any, remains authoritative.","triggerScenarios":"Rename failures in the config dir: the target held open/locked (Windows sharing violation, antivirus, indexer), `~/.openhuman` read-only or ACL-restricted, the marker path itself being a directory, or temp and target ending up on different filesystems.","commonSituations":"Windows machines with antivirus or search indexer briefly locking the marker; permission-restricted home dirs in managed environments; two processes switching workspaces at the same instant.","solutions":["Retry the workspace switch — the write is idempotent (temp+rename) and transient locks usually clear.","Check permissions on `~/.openhuman`, ensure the marker path is a file not a directory, and close/stop processes holding it open.","On Windows, exclude the `.openhuman` directory from real-time antivirus scanning or retry after the scan completes."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Probe that the config dir supports write+rename before switching workspaces\nlet dir = default_config_dir();\nlet a = dir.join(format!(\".probe-{}a\", uuid::Uuid::new_v4()));\nlet b = dir.join(format!(\".probe-{}b\", uuid::Uuid::new_v4()));\ntokio::fs::write(&a, b\"\").await?;\ntokio::fs::rename(&a, &b).await?;\nlet _ = tokio::fs::remove_file(&b).await;","typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match persist_active_workspace_marker(&state).await {\n        Ok(()) => break,\n        Err(e) if e.to_string().contains(\"atomically persist active workspace marker\") && attempt < 2 => {\n            tokio::time::sleep(std::time::Duration::from_millis(250)).await; // transient lock — retry\n        }\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["Exclude ~/.openhuman from antivirus and indexer scanning on Windows","Ensure the config dir is writable and the marker stays on one filesystem","Do not hold workspace marker files open in external tools while switching workspaces"],"tags":["config","workspace","atomic-write","filesystem","windows-file-locking"],"backgroundTag":"atomic-write-failed","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}