neondatabase/neon · critical
not implemented
Error message
not implemented
What it means
LocalFileSystem, the local-directory backend of the remote_storage crate, does not implement versioned object listing. Its list_versions() body is the unimplemented!() macro, so calling it panics at runtime ('not implemented') instead of returning a DownloadError. Version-aware listing is only provided by object stores with real versioning semantics, e.g. the S3 backend.
Source
Thrown at libs/remote_storage/src/local_fs.rs:455
cancel.cancelled().await;
Err(DownloadError::Cancelled)
};
tokio::select! {
res = op => res,
res = timeout => res,
res = cancelled => res,
}
}
async fn list_versions(
&self,
_prefix: Option<&RemotePath>,
_mode: ListingMode,
_max_keys: Option<NonZeroU32>,
_cancel: &CancellationToken,
) -> Result<crate::VersionListing, DownloadError> {
unimplemented!()
}
async fn head_object(
&self,
key: &RemotePath,
_cancel: &CancellationToken,
) -> Result<ListingObject, DownloadError> {
let target_file_path = key.with_base(&self.storage_root);
let metadata = file_metadata(&target_file_path).await?;
Ok(ListingObject {
key: key.clone(),
last_modified: metadata.modified()?,
size: metadata.len(),
})
}
async fn upload(
&self,View on GitHub (pinned to 8f60b04da4)
Solutions
- Do not enable code paths that need versioned listing against a local backend; switch the storage configuration to an S3-compatible backend if version listing is required
- Return a proper DownloadError from LocalFileSystem::list_versions instead of unimplemented!() so callers can degrade gracefully
- If you own the feature, implement list_versions for LocalFileSystem (scan suffixed/versioned files) or gate the feature on backend capabilities
Example fix
// before (libs/remote_storage/src/local_fs.rs)
async fn list_versions(...) -> Result<crate::VersionListing, DownloadError> {
unimplemented!()
}
// after
async fn list_versions(...) -> Result<crate::VersionListing, DownloadError> {
Err(DownloadError::BadInput(anyhow::anyhow!(
"list_versions is not supported by the local filesystem backend",
)))
} Defensive patterns
Strategy: validation
Validate before calling
// Before touching versioned listing, check backend capability
let supports_versions = !matches!(remote_storage_kind, RemoteStorageKind::LocalFs(_));
if !supports_versions {
return Ok(Default::default()); // skip versioned GC / listing
}
let listing = storage.list_versions(prefix, mode, max_keys, cancel).await?; Type guard
fn supports_list_versions(kind: &RemoteStorageKind) -> bool {
!matches!(kind, RemoteStorageKind::LocalFs(_))
} Try / catch
// It is a panic, not a Result: only catch_unwind can contain it if truly unavoidable
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
storage.list_versions(prefix, mode, max_keys, cancel)
}));
if res.is_err() { /* fall back to unversioned listing */ } Prevention
- Never enable version-dependent features against a local_fs backend; assert backend kind at startup
- Run integration tests for any feature that lists objects with the same backend type as production
- Treat unimplemented!()/todo!() in trait impls as panics when reviewing: replace with typed errors before shipping
When it happens
Trigger: Calling list_versions() (directly or via GenericRemoteStorage) on a storage handle constructed for LocalFileSystem, e.g. a pageserver or compute configured with a local remote_storage backend when some code path requests ListingMode with versions. Any code that enumerates object versions (versioned GC, old-version cleanup) hits the panic immediately.
Common situations: Development or test environments that use local_fs remote storage while running a feature that was only exercised against S3 (works in staging with S3, panics locally); CI jobs that toggle the storage backend; deploying with a local prefix instead of an S3 bucket.
Related errors
- Log set id's rwlock poisoned: {}
- max_keys_per_list_response can't be 0
- Azure GET response contained no response body
- Missing ETag header
- Missing LastModified header
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/9ea5241ce0d9fc74.
Report an issue: GitHub.