openai/codex · error · QueueServiceError

queue storage failed: {0}

Error message

queue storage failed: {0}

What it means

Wraps ThreadStoreError via #[from] (codex-rs/ext/queue/src/service.rs:48-49) and is returned by every QueuedItemService method that touches the underlying QueueStore: enqueue, list/list_page, update, delete, reorder, and start. The local store is SQLite-backed and converts storage-layer failures into ThreadStoreError::Internal (queue_store.rs:78-81). start() also fabricates ThreadStoreError::InvalidRequest ('queue is empty' / 'queued submission not found: {id}') when the requested item is missing (service.rs:380-385), and reorder() returns InvalidRequest when the ids are not an exact permutation of the queue.

Source

Thrown at codex-rs/ext/queue/src/service.rs:48

use codex_thread_store::QueueStore;
use codex_thread_store::QueuedUserSubmissionRecord;
use codex_thread_store::ThreadStoreError;
use thiserror::Error;
use tokio::sync::Mutex;
use tokio::sync::OwnedMutexGuard;
use tokio::sync::broadcast::error::TryRecvError;
use uuid::Uuid;

/// One user message waiting to start on its thread.
#[derive(Clone, Debug, PartialEq)]
pub struct QueuedItem {
    pub id: String,
    pub input: TurnInput,
}

#[derive(Debug, Error)]
pub enum QueueServiceError {
    #[error("queue storage failed: {0}")]
    Storage(#[from] ThreadStoreError),
    #[error("queued submission payload is invalid: {0}")]
    InvalidPayload(#[from] serde_json::Error),
    #[error("local queued attachment is invalid: {0}")]
    InvalidAttachment(#[from] std::io::Error),
    #[error("Core failed to submit queued user message: {0}")]
    CoreSubmissionError(#[from] CodexErr),
    #[error("only user input can be added to the user-message queue")]
    InvalidInput,
    #[error(
        "queued user input exceeds the maximum length of {MAX_USER_INPUT_TEXT_CHARS} characters ({actual_chars} provided)"
    )]
    InputTooLarge { actual_chars: usize },
}

#[derive(Clone)]
pub struct QueuedItemService {
    queue: Arc<dyn QueueStore>,

View on GitHub (pinned to 339751715c)

Solutions

  1. Read the inner ThreadStoreError: InvalidRequest means bad request data (fix the ids), Internal usually means SQLite-level trouble.
  2. For 'queued submission not found' or an empty queue, re-fetch with list(thread_id) and act on current ids.
  3. For reorder, pass exactly the ids returned by list(), each exactly once, in the new order.
  4. For Internal SQLite errors, check the state database's permissions, concurrent holders, and disk space.

Example fix

// before
service.reorder(thread_id, vec![first_id]).await?; // partial list => InvalidRequest

// after - ids must be the complete queue, each once, in the new order
let ids: Vec<String> = desired_order.into_iter().map(|item| item.id).collect();
service.reorder(thread_id, ids).await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust - verify a reorder payload is a permutation of the live queue before calling reorder
let current: std::collections::HashSet<String> =
    service.list(thread_id).await?.into_iter().map(|i| i.id).collect();
let next: std::collections::HashSet<String> = new_order.iter().cloned().collect();
debug_assert_eq!(current, next); // caller guarantee: every id, exactly once
service.reorder(thread_id, new_order).await

Try / catch

match service.start(thread, Some(id), None).await {
    Ok(submission) => { /* ... */ }
    Err(QueueServiceError::Storage(ThreadStoreError::InvalidRequest { message }))
        if message.contains("not found") || message.contains("empty") =>
    {
        // stale snapshot: refresh with list() and pick a current id
    }
    Err(QueueServiceError::Storage(ThreadStoreError::Internal { message })) => {
        // SQLite-level failure: check db locks, permissions, disk space
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Any queue operation hitting a SQLite error (locked database, corrupt file, disk full); reorder() with an id list that omits or duplicates queue items; start(thread, Some(id)) where the item was already dequeued by another client.

Common situations: Two processes sharing one state database (lock contention); a UI acting on a stale queue snapshot after another client consumed an item; drag-and-drop reorder that dropped an item from the list.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/a2f0c89cf67621eb. Report an issue: GitHub.