{"record":{"id":"58bea4121d76d2b2","repo":"openai/codex","slug":"path-path-is-not-a-file","errorCode":null,"errorMessage":"path '{path}' is not a file","messagePattern":"path '(.+?)' is not a file","errorType":"validation","errorClass":"MemoriesBackendError","httpStatus":null,"severity":"error","filePath":"codex-rs/ext/memories/src/backend.rs","lineNumber":155,"sourceCode":"    #[error(\"filename '{filename}' {reason}\")]\n    InvalidFilename { filename: String, reason: String },\n    #[error(\"ad-hoc note must not be empty\")]\n    EmptyAdHocNote,\n    #[error(\"ad-hoc note '{filename}' already exists\")]\n    AdHocNoteAlreadyExists { filename: String },\n    #[error(\"path '{path}' {reason}\")]\n    InvalidPath { path: String, reason: String },\n    #[error(\"cursor '{cursor}' {reason}\")]\n    InvalidCursor { cursor: String, reason: String },\n    #[error(\"path '{path}' was not found\")]\n    NotFound { path: String },\n    #[error(\"line_offset must be a 1-indexed line number\")]\n    InvalidLineOffset,\n    #[error(\"max_lines must be a positive integer\")]\n    InvalidMaxLines,\n    #[error(\"line_offset exceeds file length\")]\n    LineOffsetExceedsFileLength,\n    #[error(\"path '{path}' is not a file\")]\n    NotFile { path: String },\n    #[error(\"queries must not be empty or contain empty strings\")]\n    EmptyQuery,\n    #[error(\"all_within_lines.line_count must be a positive integer\")]\n    InvalidMatchWindow,\n    #[error(\"I/O error while reading memories: {0}\")]\n    Io(#[from] std::io::Error),\n}\n\nimpl MemoriesBackendError {\n    pub fn invalid_filename(filename: impl Into<String>, reason: impl Into<String>) -> Self {\n        Self::InvalidFilename {\n            filename: filename.into(),\n            reason: reason.into(),\n        }\n    }\n\n    pub fn invalid_path(path: impl Into<String>, reason: impl Into<String>) -> Self {","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/ext/memories/src/backend.rs#L137-L173","documentation":"Returned by the memories read path (codex-rs/ext/memories/src/local/read.rs:30-32) when the path resolves and metadata exists but the entry is not a regular file, almost always a directory. read() only returns file content; symlinks are rejected earlier by a dedicated check. The list() API marks every entry with MemoryEntryType::File or MemoryEntryType::Directory exactly so callers can avoid this.","triggerScenarios":"Calling read() on a path that list() reported as MemoryEntryType::Directory; passing the memory root or a subfolder; reading a special file (fifo, device) that exists in the store.","commonSituations":"An agent or automation enumerating the store and reading every entry without checking entry_type; assuming list() results are all files; joining a folder with an empty filename.","solutions":["Call list() first and only read entries whose entry_type is MemoryEntryType::File.","To inspect a directory, list() it with the directory as path.","To locate content across files, use search(), which walks directories itself."],"exampleFix":"// before\nfor entry in backend.list(list_req).await?.entries {\n    let resp = backend.read(read_req(entry.path)).await?; // NotFile on directories\n}\n\n// after\nfor entry in backend.list(list_req).await?.entries {\n    if is_memory_file(&entry) {\n        let resp = backend.read(read_req(entry.path)).await?;\n    }\n}","handlingStrategy":"type-guard","validationCode":"// Rust - filter a listing down to readable files before calling read\nlet entries = backend.list(ListMemoriesRequest { path: Some(dir), cursor: None, max_results: 100 }).await?;\nlet readable: Vec<_> = entries.entries.into_iter().filter(is_memory_file).collect();","typeGuard":"// Rust - narrow MemoryEntry to entries read() accepts\nfn is_memory_file(entry: &MemoryEntry) -> bool {\n    matches!(entry.entry_type, MemoryEntryType::File)\n}","tryCatchPattern":null,"preventionTips":["Check MemoryEntryType before read(); directories are valid inputs only to list() and search().","Never assume every list() result is a file.","Prefer search() for content discovery instead of read()-ing every path."],"tags":["rust","codex","memories","filesystem","validation","eisdir"],"backgroundTag":"path-is-directory","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}