Skip to main content

Limitations

Oyster implements the most commonly used S3 operations. Some features and behaviors differ from a full AWS S3 deployment.

Which S3 features does Oyster support?​

FeatureStatusNotes
CreateBucketSupported
HeadBucketSupported
ListBucketsSupportedMax 1000, no pagination
DeleteBucketSupportedRequires empty bucket (same as AWS S3)
PutObjectSupportedSingle-part only, max 1GB
GetObjectSupported
HeadObjectSupported
DeleteObjectSupported
ListObjectsV2SupportedPrefix, delimiter, pagination
Conditional requestsSupportedIf-Match, If-None-Match on PutObject, GetObject, and HeadObject; DeleteObject supports If-Match only
Multipart uploadNot supportedUse single PutObject (max 1GB)
CopyObjectNot supportedDownload and re-upload instead
DeleteObjects (batch)Not supportedDelete one at a time
Object versioningNot supportedOverwrite replaces the object
Bucket policiesNot supported
ACLsNot supported
CORSNot supported
Server-side encryptionNot supportedOyster stores data unencrypted
Object taggingSupportedget/put/delete; shares tags with JSON API
Custom metadata headersNot supportedOyster stores only Content-Type
Website hostingNot supported
S3 SelectNot supported
Storage classesNot supportedAll objects are STANDARD
Transfer AccelerationNot supported
Inventory and AnalyticsNot supported
Object Lock and Legal HoldNot supported
Lifecycle rulesNot supportedSee Object expiration

How does Oyster behave differently from AWS S3?​

Object expiration​

All objects in a bucket share the owning account's StoragePool lifetime, with no per-object expiration to set. Oyster runs a background extension service that renews the pool before it expires, so objects persist indefinitely as long as the service is running and the account's wallet stays funded. See Blob Lifecycle for the model.

Bucket naming​

Oyster's bucket naming rules are slightly stricter than AWS S3:

RuleAWS S3Oyster
Dots (.) in namesAllowedNot allowed
Underscores (_) in namesAllowedNot allowed
Consecutive hyphens (--)AllowedNot allowed
Reserved namesNonehealth, ready, metrics, api

ListBuckets limit​

ListBuckets returns a maximum of 1000 buckets with no pagination support.

Path-style URLs only​

Oyster only supports path-style S3 URLs:

http://endpoint/bucket-name/key

Oyster does not support virtual-hosted-style URLs (bucket-name.endpoint/key). Always set force_path_style: true in your SDK configuration. For full client setup, see S3 setup.

No region semantics​

Oyster ignores the region in S3 requests. Oyster stores all data in the same location. You still need to specify a region for SigV4 signing to work, so use any valid region string, for example us-east-1.

ETag format​

ETags are always the MD5 digest of the object content, even for large objects. There is no multipart ETag format, because Oyster does not support multipart upload.

Conditional request headers​

Oyster supports If-Match and If-None-Match headers on PutObject, GetObject, HeadObject, and DeleteObject (If-Match only). These enable cache validation (If-None-Match returns 304 on GET or HEAD) and safe concurrent writes (If-Match for optimistic locking, If-None-Match: * for create-only semantics). Oyster does not support time-based conditionals (If-Modified-Since, If-Unmodified-Since).

How to set path-style URLs in the Rust SDK​

In the AWS SDK for Rust (aws-sdk-s3), call force_path_style(true) on the config builder. The following client configuration also sets the region and endpoint:

use aws_sdk_s3::config::{Credentials, Region};

let creds = Credentials::new(
"OYAK1234567890ABCDEF",
"abcdef1234567890...",
None, None, "oyster",
);

let config = aws_sdk_s3::Config::builder()
.behavior_version_latest()
.region(Region::new("us-east-1"))
.endpoint_url("http://localhost:3000")
.credentials_provider(creds)
.force_path_style(true)
.build();

let client = aws_sdk_s3::Client::from_conf(config);

Other SDKs expose an equivalent path-style option. For full client setup, see S3 setup.