{"record":{"id":"7a99fb00c6794024","repo":"xai-org/grok-build","slug":"failed-to-replace-e","errorCode":null,"errorMessage":"failed to replace {}: {e}","messagePattern":"failed to replace (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-workspace/src/hub_auth/mod.rs","lineNumber":374,"sourceCode":"    #[cfg(unix)]\n    {\n        use std::os::unix::fs::OpenOptionsExt;\n        opts.mode(0o600);\n    }\n\n    let mut file = opts\n        .open(&tmp)\n        .map_err(|e| anyhow::anyhow!(\"failed to open {}: {e}\", tmp.display()))?;\n    file.write_all(json.as_bytes())?;\n    file.sync_all()?;\n    drop(file);\n\n    #[cfg(windows)]\n    let _ = std::fs::remove_file(path);\n\n    if let Err(e) = std::fs::rename(&tmp, path) {\n        let _ = std::fs::remove_file(&tmp);\n        return Err(anyhow::anyhow!(\"failed to replace {}: {e}\", path.display()));\n    }\n    Ok(())\n}\n\n/// Build a hub auth provider for `hub_url`. `auth_config` overrides\n/// the default credential path (`~/.grok/auth.json`).\n///\n/// `refresh_cfg.enabled` selects the workspace-owned proactive refresher;\n/// when off (the default) this is the SDK `OidcAuthProvider`. Loopback\n/// `ws://` ignores the flag and stays on a static bearer.\npub fn provider(\n    hub_url: &Url,\n    auth_config: Option<&Path>,\n    refresh_cfg: &ProactiveRefreshConfig,\n) -> anyhow::Result<Arc<dyn AuthProvider>> {\n    let auth_path = match auth_config {\n        Some(p) => p.to_path_buf(),\n        None => default_auth_path()?,","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-workspace/src/hub_auth/mod.rs#L356-L392","documentation":"`write_json_atomic` finishes by `std::fs::rename(tmp, path)` to atomically replace auth.json. This error is thrown when the rename fails; the temp file is cleaned up first. Typical wrapped io::Errors are cross-device link errors, permission problems on the destination, or on Windows the destination being locked by another process.","triggerScenarios":"`write_refreshed_token` -> `write_json_atomic` when `fs::rename(&tmp, path)` returns Err: destination directory not writable, destination file locked (Windows), tmp and destination on different filesystems, or destination removed/replaced concurrently by another process.","commonSituations":"Two grok processes refreshing simultaneously and one deletes/locks the file; ~/.grok on a different mount than a symlinked temp dir; Windows Defender briefly holding auth.json; read-only home mount.","solutions":["Check write permissions on the directory and existing auth.json (`ls -ld ~/.grok ~/.grok/auth.json`).","Retry the refresh — the atomic rename is designed to be safe to repeat; transient locks usually clear.","Ensure tmp and auth.json live on the same filesystem (do not symlink ~/.grok across mounts).","On Windows, close tools holding auth.json open (editors, sync clients) and exclude the directory from real-time AV scanning."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Rename failures are often transient (locks, concurrent refresh); retry with backoff\nfor attempt in 0..3 {\n    match write_refreshed_token(&auth_path, &scope_key, &event) {\n        Ok(()) => break,\n        Err(e) if attempt < 2 && e.to_string().contains(\"failed to replace\") => {\n            std::thread::sleep(std::time::Duration::from_millis(100 * (attempt + 1)));\n        }\n        Err(e) => { tracing::warn!(error = %e, \"token persist failed\"); break; }\n    }\n}","preventionTips":["Don't run multiple refresh-capable clients against the same GROK_HOME concurrently.","Keep ~/.grok and its temp files on the same filesystem — no cross-mount symlinks.","On Windows, exclude auth.json from real-time scanners that hold files open during rename.","Remember a failed persist only loses the newest token; the in-memory access token still works until expiry."],"tags":["filesystem","io","atomic-write","rust"],"backgroundTag":"file-replace-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}