Fixing Silent Storage Misconfiguration in v1.0.21
Fixing Silent Storage Misconfiguration in v1.0.21
Version 1.0.21 corrects a documentation mismatch between the environment variables that the storage client actually reads and the variables that were listed in .env.example. This post explains what went wrong, why it was hard to spot, and exactly what you need to do if you operate your own deployment.
Background
The platform's object-storage layer lives in src/platform/storage/client.ts. The client resolves two key pieces of configuration at runtime:
// src/platform/storage/client.ts (simplified)
const bucket = process.env.BUCKET_NAME ?? 'uploads';
const endpoint = process.env.AWS_ENDPOINT_URL_S3; // undefined → AWS global S3
The ?? (nullish coalescing) operator means that if BUCKET_NAME is not set in the environment, the client silently continues using a bucket literally named uploads. Similarly, if AWS_ENDPOINT_URL_S3 is absent, the AWS SDK defaults to the global AWS S3 endpoint — which is incorrect for any S3-compatible provider such as Tigris, MinIO, or Cloudflare R2.
The Problem
Before this release, .env.example contained:
# Storage
AWS_S3_BUCKET=your-bucket-name
AWS_S3_BUCKET is not read anywhere in the codebase. An operator who copied .env.example and filled in their bucket name under AWS_S3_BUCKET would have no warning that the value was being ignored. The two concrete failure modes were:
- Wrong bucket — All uploads land in
uploads(the hardcoded fallback) instead of the configured bucket. Depending on bucket permissions this may fail silently or succeed, sending data to an unintended location. - Wrong endpoint — For deployments using a Tigris or other S3-compatible endpoint, the
AWS_ENDPOINT_URL_S3variable was never documented. Requests would be sent tos3.amazonaws.cominstead, resulting in authentication failures or, worse, unexpected cross-provider traffic.
Both failures are silent — no exception is thrown at startup and no warning is logged unless the resulting SDK call itself fails.
The Fix
.env.example has been updated to accurately reflect what the code reads:
# Storage
# Name of the S3 bucket to use for uploads.
BUCKET_NAME=your-bucket-name
# S3-compatible endpoint URL. Required when using Tigris, MinIO, Cloudflare R2, etc.
# For Tigris on Fly.io: https://fly.storage.tigris.dev
AWS_ENDPOINT_URL_S3=https://fly.storage.tigris.dev
The stale AWS_S3_BUCKET entry has been removed.
Action Required
If you manage a deployed instance, audit your environment variables before or immediately after upgrading to v1.0.21.
Step 1 — Rename the bucket variable
# Before
AWS_S3_BUCKET=my-production-bucket
# After
BUCKET_NAME=my-production-bucket
Step 2 — Add the endpoint variable
Set AWS_ENDPOINT_URL_S3 to your provider's endpoint:
| Provider | Endpoint URL |
|---|---|
| Tigris (Fly.io) | https://fly.storage.tigris.dev |
| MinIO (self-hosted) | http://your-minio-host:9000 |
| Cloudflare R2 | https://<account-id>.r2.cloudflarestorage.com |
| AWS S3 (standard) | (omit the variable — SDK defaults are correct) |
Step 3 — Verify
After updating your environment, restart the application and perform a test upload. Confirm the file appears in the correct bucket on the correct provider.
Why This Matters
Silent configuration fallbacks are particularly dangerous in storage systems because:
- Data written to the wrong bucket may not be immediately noticed.
- Recovering misplaced uploads from a fallback bucket can be operationally expensive.
- Cross-provider traffic (hitting AWS when you intended Tigris) may incur unexpected costs or expose data to unintended regions.
This fix removes the ambiguity entirely by aligning the documentation with the code.