JuliusBrussee/caveman · error · ErrPagingUnsupported
objectstore: paged listing unsupported
Error message
objectstore: paged listing unsupported
What it means
objectstore.ErrPagingUnsupported is returned when paged listing (ListPage or the ListPage helper) is called on a backend that does not implement the PagedLister cursor interface, or when a Memory-backend ListPage is given maxKeys <= 0. Callers that must bound listing memory need a cursor-capable backend; this error makes that requirement explicit.
Solutions
- Use a backend that implements PagedLister (the MinIO/S3 store) wherever bounded listing is required.
- If using Memory, pass a positive maxKeys, or replace it with a paged-capable store for that code path.
- If you wrote a custom Store, implement the PagedLister interface's ListPage method.
- Fall back to unbounded List for small/test datasets only, accepting the memory tradeoff.
Example fix
// before
page, err := objectstore.ListPage(ctx, memStore, prefix, "", 100) // Memory with maxKeys ok, but non-paged backends fail
// after
if _, ok := store.(objectstore.PagedLister); !ok {
return fmt.Errorf("listing requires a paged backend")
}
page, err := objectstore.ListPage(ctx, store, prefix, "", 100) Defensive patterns
Strategy: type-guard
Validate before calling
if maxKeys <= 0 { return errors.New("maxKeys must be positive") } Type guard
func supportsPaging(s objectstore.Store) bool {
_, ok := s.(objectstore.PagedLister)
return ok
} Try / catch
page, err := objectstore.ListPage(ctx, store, prefix, startAfter, maxKeys)
if errors.Is(err, objectstore.ErrPagingUnsupported) {
return errors.New("bounded listing requires a PagedLister backend")
} Prevention
- Assert PagedLister at startup when the code path requires bounded listing
- Keep test (Memory) and production (S3) backends interface-compatible or gate on capability
- Never pass maxKeys <= 0 to ListPage
When it happens
Trigger: Calling objectstore.ListPage with a Store that does not implement PagedLister (objectstore.go:79 type assertion fails); calling (*Memory).ListPage with maxKeys <= 0 (memory.go:84); using an in-memory or otherwise non-paged backend where the caller expects S3-style pagination.
Common situations: Swapping the object store backend from MinIO/S3 to the in-memory implementation (tests, local dev) while production code path assumes paged listing; accidentally passing zero or a negative maxKeys; adding a new custom Store implementation that forgot the cursor methods.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- MCP changes require the ownership transaction
- cannot safely launch non-Node Windows command shim
- cave_claude_subagent_bridge_unavailable
- cave_memory_shared_backend_unavailable
- cave_subagent_framework_runner_required
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/348cbc72456682fd.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/objectstore/objectstore.go:39
"time"
"github.com/JuliusBrussee/caveman/shared/platform/env"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
// ErrNotFound is returned by Get/Delete when the key does not exist.
var ErrNotFound = errors.New("objectstore: object not found")
// ErrTooLarge is returned when a remote object exceeds the configured in-memory
// read ceiling. Artifact/capture payloads are bounded on write; enforcing a
// read ceiling too prevents a corrupted or attacker-written bucket object from
// exhausting a service process.
var ErrTooLarge = errors.New("objectstore: object exceeds read limit")
// ErrPagingUnsupported is returned when a caller that must bound listing
// memory is given a backend without a cursor-capable implementation.
var ErrPagingUnsupported = errors.New("objectstore: paged listing unsupported")
// Store is the blob backend contract.
type Store interface {
// Put writes body at key, overwriting any existing object.
Put(ctx context.Context, key string, body []byte, contentType string) error
// Get returns the bytes at key, or ErrNotFound.
Get(ctx context.Context, key string) ([]byte, error)
// Delete removes key (no error if already absent).
Delete(ctx context.Context, key string) error
// Exists reports whether key is present.
Exists(ctx context.Context, key string) (bool, error)
// List returns all keys under prefix (used by retention + ZDR assertions).
List(ctx context.Context, prefix string) ([]string, error)
}
// ObjectPage is one bounded, lexicographically ordered page of keys. NextToken
// is safe to persist as a cursor; it is empty when the prefix is exhausted.
type ObjectPage struct {View on GitHub (pinned to 3ee70a1026)