{"record":{"id":"f6ed9b6fdc972459","repo":"rustfs/rustfs","slug":"storage-not-available-0","errorCode":null,"errorMessage":"Storage not available: {0}","messagePattern":"Storage not available: (.+?)","errorType":"exception","errorClass":"AuditError","httpStatus":null,"severity":"error","filePath":"crates/audit/src/error.rs","lineNumber":41,"sourceCode":"    #[error(\"Configuration error: {0}\")]\n    Configuration(String, #[source] Option<Box<dyn std::error::Error + Send + Sync>>),\n\n    #[error(\"config not loaded\")]\n    ConfigNotLoaded,\n\n    #[error(\"Target error: {0}\")]\n    Target(#[from] rustfs_targets::TargetError),\n\n    #[error(\"System not initialized: {0}\")]\n    NotInitialized(String),\n\n    #[error(\"System already initialized\")]\n    AlreadyInitialized,\n\n    #[error(\"Audit system is paused; entry was not accepted\")]\n    Paused,\n\n    #[error(\"Storage not available: {0}\")]\n    StorageNotAvailable(String),\n\n    #[error(\"Failed to save configuration: {0}\")]\n    SaveConfig(#[source] Box<dyn std::error::Error + Send + Sync>),\n\n    #[error(\"Failed to load configuration: {0}\")]\n    LoadConfig(#[source] Box<dyn std::error::Error + Send + Sync>),\n\n    #[error(\"Serialization error: {0}\")]\n    Serialization(#[from] serde_json::Error),\n\n    #[error(\"I/O error: {0}\")]\n    Io(#[from] std::io::Error),\n\n    #[error(\"Join error: {0}\")]\n    Join(#[from] tokio::task::JoinError),\n}\n","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/rustfs/rustfs/blob/35af688cd9d41b4346fbe27dcf7250ba72046c1f/crates/audit/src/error.rs#L23-L59","documentation":"Index::find() (crates/rio/src/compress_index.rs:150) needs at least one index entry to map an offset to a block. If index.info is empty — the index was constructed but add() was never called (or the stream was too small to record any entry, since entries closer than MIN_INDEX_DIST are skipped) — find() returns UnexpectedEof 'empty index' regardless of the offset being in bounds.","triggerScenarios":"Calling find() on a fresh Index::new(); loading an index chunk that legitimately contains zero entries (tiny streams where every add was suppressed by the MIN_INDEX_DIST rule); forgetting to call load()/load_stream() before find().","commonSituations":"Small-object fast path skipping index building but still calling find(); deserialization succeeded but read the wrong byte range; race where a reader seeks before the writer finished the first index entry.","solutions":["Skip seek-index lookups when index.is_empty() and fall back to a linear decode from stream start.","Ensure load()/load_stream() ran successfully (and its byte range actually contained the index chunk) before find().","For small objects, store/stream without an index or synthesize a single (0,0) entry.","Guard with is_empty() in callers: if index.is_empty() { decode_from_start() } else { index.find(off)? }."],"exampleFix":"// before\nlet (c, u) = index.find(offset)?; // panics path if index empty\n\n// after: fall back to linear read\nlet (c, u) = if index.is_empty() {\n    (0i64, 0i64)\n} else {\n    index.find(offset)?\n};","handlingStrategy":"fallback","validationCode":"if index.is_empty() {\n    // no seek index for this object: decode linearly from the start\n    return decode_from_start(&stream);\n}\nlet (c, u) = index.find(offset)?;","typeGuard":"fn index_has_entries(index: &Index) -> bool {\n    !index.is_empty()\n}","tryCatchPattern":"match index.find(offset) {\n    Ok(pos) => pos,\n    Err(e) if e.kind() == io::ErrorKind::UnexpectedEof && e.to_string().contains(\"empty index\") => {\n        decode_from_start(&stream) // fallback: no entries recorded\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Check index.is_empty() before find() and keep a linear-decode fallback.","Ensure load()/load_stream() completed and the byte range actually contained the chunk.","Tiny streams may legitimately have no entries — design the read path for that."],"tags":["rust","compression","s2","index","empty-state","unexpected-eof"],"backgroundTag":"compression-index-empty","analyzedSha":"35af688cd9d41b4346fbe27dcf7250ba72046c1f","analyzedAt":"2026-08-20T21:57:04.799Z","contentChangedAt":"2026-08-20T21:57:04.799Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}