{"record":{"id":"d308e55bda1ff8e9","repo":"BigPizzaV3/CodexPlusPlus","slug":"monitor-lock-is-a-reparse-point","errorCode":null,"errorMessage":"Monitor lock is a reparse point","messagePattern":"Monitor lock is a reparse point","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/native_browser.rs","lineNumber":743,"sourceCode":"        \"Backups must be outside the cache\"\n    );\n    fs::create_dir_all(&paths.state_root)?;\n    let path = paths.state_root.join(\"monitor.lock\");\n    let _guards = pin_parents(&path)?;\n    let mut options = OpenOptions::new();\n    options.read(true).write(true).create(true).truncate(false);\n    #[cfg(windows)]\n    {\n        use std::os::windows::fs::OpenOptionsExt;\n        options.share_mode(0x1 | 0x2).custom_flags(0x00200000);\n    }\n    let owner = options.open(&path)?;\n    let meta = owner.metadata()?;\n    ensure!(meta.is_file(), \"Unexpected monitor lock type\");\n    #[cfg(windows)]\n    {\n        use std::os::windows::fs::MetadataExt;\n        ensure!(meta.file_attributes() & 0x400 == 0, \"Monitor lock is a reparse point\");\n    }\n    plain_path(&path)?;\n    owner.try_lock_exclusive().context(\"Another native browser monitor is active\")?;\n    Ok(owner)\n}\n\n/// Called after Codex has been stopped, before the manager launches a replacement.\n/// Never restores files itself or creates a lock for an older launcher.\npub fn wait_for_monitor_shutdown(timeout: Duration) -> Result<()> {\n    if !cfg!(windows) {\n        return Ok(());\n    }\n    let paths = BrowserPaths::current()?;\n    wait_for_monitor_shutdown_at(&paths, timeout)\n}\n\nfn wait_for_monitor_shutdown_at(paths: &BrowserPaths, timeout: Duration) -> Result<()> {\n    let path = paths.state_root.join(\"monitor.lock\");","sourceCodeStart":725,"sourceCodeEnd":761,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/native_browser.rs#L725-L761","documentation":"On Windows, after confirming monitor.lock is a regular file, acquire_monitor_owner additionally rejects files whose FILE_ATTRIBUTE_REPARSE_POINT bit (0x400) is set — junctions, symlinks, OneDrive/cloud placeholders, and similar. This is an anti-symlink-attack / anti-placeholder hardening check: a reparse point could redirect the lock to a location controlled by someone else or behave unpredictably under file locking, so the library refuses to use it.","triggerScenarios":"Calling start_monitor_with_contract on Windows when `<state_root>/monitor.lock` carries the reparse-point attribute — e.g. the state directory was replaced with an NTFS junction or symlink, the file is a OneDrive/Files-On-Demand placeholder, or a dev-drive/symlink setup put the lock behind a reparse point.","commonSituations":"State directory relocated via junction/symlink (common with Dotfiles or moving state off an SSD); OneDrive/Dropbox 'files on demand' placeholder attributes; corporate roaming profiles with folder redirection; WSL/Windows interop creating symlinks.","solutions":["Check the attribute: `fsutil reparsepoint query <state_root>\\monitor.lock` or `attrib <path>` and look for reparse/L attributes.","Move the state directory to a real local NTFS path (not a junction/symlink/cloud-synced folder) and update the configuration pointing at it.","Dehydrate/convert OneDrive placeholders to local files, or exclude the CodexPlusPlus state dir from cloud sync.","Replace monitor.lock with a plain regular file (delete and let the library recreate it) once the state root is a plain directory."],"exampleFix":"// before: state dir is a junction\nmklink /J %APPDATA%\\codex-state D:\\sync\\codex-state\n// after: real local directory, not cloud-synced\nmkdir %APPDATA%\\codex-state  (copy contents, remove the junction)","handlingStrategy":"validation","validationCode":"// Windows-only preflight\n#[cfg(windows)]\nfn has_reparse_point(p: &std::path::Path) -> bool {\n    use std::os::windows::fs::MetadataExt;\n    std::fs::symlink_metadata(p).map(|m| m.file_attributes() & 0x400 != 0).unwrap_or(false)\n}\n// refuse to use a state root (or lock path) that is a junction/symlink/cloud placeholder","typeGuard":"#[cfg(windows)]\nfn is_plain_local_file(p: &std::path::Path) -> bool {\n    use std::os::windows::fs::MetadataExt;\n    std::fs::metadata(p).map(|m| m.is_file() && m.file_attributes() & 0x400 == 0).unwrap_or(false)\n}","tryCatchPattern":"match start_monitor(&paths, enabled) {\n    Err(e) if e.to_string().contains(\"reparse point\") => {\n        // relocate state dir to a real local NTFS path and retry\n    }\n    other => other?,\n}","preventionTips":["Do not relocate the state directory with NTFS junctions or symlinks","Exclude the CodexPlusPlus state directory from OneDrive/Dropbox placeholders and cloud sync","Preflight the state root on Windows for the 0x400 reparse attribute before starting monitors"],"tags":["windows","symlink","security","lock-file"],"backgroundTag":"path-traversal-blocked","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}