openai/codex · error · MemoriesBackendError
cursor '{cursor}' {reason}
Error message
cursor '{cursor}' {reason} What it means
A pagination cursor passed to list or search failed validation — the reason says whether it was malformed, unknown, or belongs to a different listing. Cursors are opaque tokens minted by the backend, not free-form offsets.
Source
Thrown at codex-rs/ext/memories/src/backend.rs:145
pub struct MemorySearchMatch {
pub path: String,
pub match_line_number: usize,
pub content_start_line_number: usize,
pub content: String,
pub matched_queries: Vec<String>,
}
#[derive(Debug, thiserror::Error)]
pub enum MemoriesBackendError {
#[error("filename '{filename}' {reason}")]
InvalidFilename { filename: String, reason: String },
#[error("ad-hoc note must not be empty")]
EmptyAdHocNote,
#[error("ad-hoc note '{filename}' already exists")]
AdHocNoteAlreadyExists { filename: String },
#[error("path '{path}' {reason}")]
InvalidPath { path: String, reason: String },
#[error("cursor '{cursor}' {reason}")]
InvalidCursor { cursor: String, reason: String },
#[error("path '{path}' was not found")]
NotFound { path: String },
#[error("line_offset must be a 1-indexed line number")]
InvalidLineOffset,
#[error("max_lines must be a positive integer")]
InvalidMaxLines,
#[error("line_offset exceeds file length")]
LineOffsetExceedsFileLength,
#[error("path '{path}' is not a file")]
NotFile { path: String },
#[error("queries must not be empty or contain empty strings")]
EmptyQuery,
#[error("all_within_lines.line_count must be a positive integer")]
InvalidMatchWindow,
#[error("I/O error while reading memories: {0}")]
Io(#[from] std::io::Error),
}View on GitHub (pinned to 339751715c)
Solutions
- Only pass the next_cursor returned by the immediately preceding call of the same query.
- On InvalidCursor, restart pagination from the first page (cursor None).
- Treat cursor strings as opaque — never construct or mutate them.
Defensive patterns
Strategy: validation
Validate before calling
// Only ever forward the opaque token from the previous same-query response let cursor = previous.next_cursor.clone(); // On any pagination restart, send cursor: None instead of a remembered token
Try / catch
match backend.list(req).await {
Err(MemoriesBackendError::InvalidCursor { cursor, reason }) => {
tracing::warn!(%cursor, %reason, "stale cursor; restarting from first page");
backend.list(req_with_first_page).await
}
r => r,
} Prevention
- Treat cursors as opaque — never build or edit them.
- Scope a cursor to the exact query that produced it; do not reuse across list/search.
- Restart from page one on cursor invalidation instead of failing the whole listing.
When it happens
Trigger: Reusing a next_cursor from an earlier or different query, editing or truncating a cursor string, or continuing pagination after the store changed underneath.
Common situations: Resuming a listing from stale saved state; mixing cursors between list and search; concurrent modifications invalidating tokens.
Related errors
- max_lines must be a positive integer
- line_offset exceeds file length
- filename '{filename}' {reason}
- ad-hoc note must not be empty
- ad-hoc note '{filename}' already exists
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/679ce417d950c72b.
Report an issue: GitHub.