influxdata/influxdb · error · Error

wal is shutdown and not accepting writes

Error message

wal is shutdown and not accepting writes

What it means

Error::Shutdown is raised by the influxdb3_wal WriteBuffer once the WAL has been shut down and will no longer persist incoming writes. After shutdown, buffering a write would silently drop data, so the library rejects any new write with this error. It signals a lifecycle violation: writes must stop before (or be routed away from) a shutdown WAL.

Solutions

  1. Stop sending writes once shutdown() has been called; check the WAL/buffer state before issuing writes in embedded usage.
  2. Drain in-flight write requests before calling shutdown, and return a clean error to clients during the draining window.
  3. Treat this error as a client-side signal to stop retrying and report 'server is shutting down' to the user.
  4. In application code, guard with a lifecycle flag or channel closed check so writes are never issued post-shutdown.

Example fix

// before
wal.shutdown().await;
wal.write_buffer(buffer, Gen1Duration::default()).await?; // panics/errors: wal is shutdown
// after
wal.shutdown().await;
if !wal.is_shutdown() {
    wal.write_buffer(buffer, Gen1Duration::default()).await?;
} else {
    return Err("server is shutting down; write rejected");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// embedded usage: check state before writing
if wal.is_shutdown() {
    return Err(WriteRejected::ShuttingDown);
}

Type guard

fn is_shutdown(err: &influxdb3_wal::Error) -> bool { matches!(err, influxdb3_wal::Error::Shutdown) }

Try / catch

match wal.write_buffer(buffer, gen1).await {
    Err(influxdb3_wal::Error::Shutdown) => /* stop retrying, signal shutdown to client */,
    Err(e) => return Err(e.into()),
    Ok(_) => {},
}

Prevention

When it happens

Trigger: Calling write_buffer (or another write-path method) on a WalObjectStore/WriteBuffer whose state has been set to ShuttingDown/Shut down, typically after wal_buffer.shutdown() was invoked or the server is stopping.

Common situations: A write request races with a graceful server shutdown; a caller keeps a WriteBuffer handle alive after calling shutdown; tests or embedded users issuing writes after teardown; double-shutdown followed by a straggler write from an open connection.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19). Data as JSON: /api/errors/13a89a68b02d19b1. Report an issue: GitHub.

Appendix: source

Thrown at influxdb3_wal/src/lib.rs:52

#[derive(Debug, Error)]
pub enum Error {
    #[error("wal buffer full with {0} ops")]
    BufferFull(usize),

    #[error("error writing wal file: {0}")]
    WriteError(String),

    #[error("deserialize error: {0}")]
    Serialize(#[from] crate::serialize::Error),

    #[error("join error: {0}")]
    Join(#[from] tokio::task::JoinError),

    #[error("object store error: {0}")]
    ObjectStoreError(#[from] ::object_store::Error),

    #[error("wal is shutdown and not accepting writes")]
    Shutdown,

    #[error("invalid gen1 duration {0}. Must be one of 1m, 5m, 10m")]
    InvalidGen1Duration(String),

    #[error("invalid WAL file path")]
    InvalidWalFilePath,
}

pub type Result<T, E = Error> = std::result::Result<T, E>;

#[async_trait]
pub trait Wal: Debug + Send + Sync + 'static {
    /// Buffer writes ops into the buffer, but returns before the operation is persisted to the WAL.
    async fn write_ops_unconfirmed(&self, op: Vec<WalOp>) -> Result<(), Error>;

    /// Writes the ops into the buffer and waits until the WAL file is persisted. When this returns
    /// the operations are durable in the configured object store and the file notifier has been

View on GitHub (pinned to 06200ef96b)