{"record":{"id":"d0a45546a3c176da","repo":"openai/codex","slug":"current-time-request-failed-code-message","errorCode":null,"errorMessage":"current-time request failed: code={} message={}","messagePattern":"current-time request failed: code=(.+?) message=(.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/app-server/src/current_time.rs","lineNumber":120,"sourceCode":"    let connection_ids = thread_state_manager\n        .subscribed_connection_ids(thread_id)\n        .await;\n    let connection_id = require_single_current_time_connection(&connection_ids)?;\n    let connection_ids = [connection_id];\n    let (request_id, rx) = outgoing\n        .send_request_to_connections(\n            Some(&connection_ids),\n            ServerRequestPayload::CurrentTimeRead(CurrentTimeReadParams {\n                thread_id: thread_id.to_string(),\n            }),\n            /*thread_id*/ None,\n        )\n        .await;\n\n    let result = match timeout_at(deadline, rx).await {\n        Ok(Ok(Ok(result))) => result,\n        Ok(Ok(Err(err))) => {\n            bail!(\n                \"current-time request failed: code={} message={}\",\n                err.code,\n                err.message\n            );\n        }\n        Ok(Err(err)) => bail!(\"current-time request was canceled: {err}\"),\n        Err(_) => {\n            let _canceled = outgoing.cancel_request(&request_id).await;\n            bail!(\n                \"current-time request timed out after {}s\",\n                CURRENT_TIME_REQUEST_TIMEOUT.as_secs()\n            );\n        }\n    };\n    let response: CurrentTimeReadResponse =\n        serde_json::from_value(result).context(\"invalid current-time response\")?;\n\n    DateTime::from_timestamp(response.current_time_at, 0)","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/app-server/src/current_time.rs#L102-L138","documentation":"History reads take a shared lock with try_lock_shared, sleeping RETRY_SLEEP between attempts; when every attempt hits WouldBlock — a writer has held the exclusive lock for the entire window — lookup_batch gives up with ErrorKind::WouldBlock (codex-rs/message-history/src/batch.rs:131). This is a contention signal, not corruption: the file is fine, another process is writing to it for too long.","triggerScenarios":"search_batch / batch_for reads colliding with a long append/trim: append_entry holds the exclusive lock while rewriting a max_bytes-capped history file, so readers starve for the whole retry window.","commonSituations":"Multiple codex processes sharing one history file under the same CODEX_HOME; history grown to the byte cap so every append rewrites the whole file under lock; slow disks stretching lock hold time.","solutions":["Retry the search after the writer finishes — the error is transient by design.","Reduce the number of concurrent processes sharing the same history file.","Lower the history max-bytes setting so trims under lock finish quickly.","If persistent, check for a stuck process holding the lock (lsof on the history and lock files)."],"exampleFix":"// before\nlet batch = lookup_batch(&mut file, cursor, &config)?;\n// after: treat WouldBlock as transient contention\nlet batch = match lookup_batch(&mut file, cursor, &config) {\n    Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {\n        std::thread::sleep(std::time::Duration::from_millis(250));\n        lookup_batch(&mut file, cursor, &config)?\n    }\n    r => r?,\n};","handlingStrategy":"retry","validationCode":"use fs2::FileExt;\n\nfn history_lock_free(path: &std::path::Path) -> bool {\n    match std::fs::File::open(path) {\n        Ok(f) => f.try_lock_exclusive().is_ok(),\n        Err(_) => false,\n    }\n}","typeGuard":null,"tryCatchPattern":"let mut attempt = 0;\nloop {\n    match lookup_batch(&mut file, cursor, &config) {\n        Err(e) if e.kind() == std::io::ErrorKind::WouldBlock && attempt < 5 => {\n            attempt += 1;\n            std::thread::sleep(RETRY_SLEEP * attempt as u32);\n        }\n        r => break r?,\n    }\n}","preventionTips":["Treat WouldBlock from history APIs as retryable, never as data loss.","Serialize history access per user/machine — one writer at a time.","Keep history under the byte cap so locked rewrites finish quickly."],"tags":["file-lock","concurrency","history","wouldblock","rust"],"backgroundTag":"file-lock-contention","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}