usememos/memos · error
storageSetting.s3Config is required for S3
Error message
storageSetting.s3Config is required for S3
What it means
Thrown when a STORAGE instance-setting file sets storageType to S3 but provides neither s3Config nor any entries in the storages list. The code comment explains the intent: normalization would silently self-heal this to LOCAL storage, so the validator fails loudly instead, preventing an operator's S3 data from silently going to local disk. Startup aborts.
Source
Thrown at store/deployment_config.go:239
func validateAndNormalizeDeploymentInstanceSetting(setting *storepb.InstanceSetting) error {
switch setting.Key {
case storepb.InstanceSettingKey_GENERAL:
if setting.GetGeneralSetting() == nil {
return errors.New("generalSetting must be populated for key GENERAL")
}
if offset := setting.GetGeneralSetting().WeekStartDayOffset; offset < -1 || offset > 6 {
return errors.New("generalSetting.weekStartDayOffset must be between -1 and 6")
}
case storepb.InstanceSettingKey_STORAGE:
storage := setting.GetStorageSetting()
if storage == nil {
return errors.New("storageSetting must be populated for key STORAGE")
}
// Normalization would silently self-heal this misconfiguration to LOCAL;
// a deployment file declaring S3 without a config should fail loudly.
if storage.StorageType == storepb.InstanceStorageSetting_S3 && storage.S3Config == nil && len(storage.Storages) == 0 {
return errors.New("storageSetting.s3Config is required for S3")
}
NormalizeInstanceStorageSetting(storage)
if storage.UploadSizeLimitMb < 0 {
return errors.New("storageSetting.uploadSizeLimitMb must not be negative")
}
defaultStorage := GetDefaultStorage(storage)
if defaultStorage != nil && defaultStorage.Type == storepb.StorageType_STORAGE_TYPE_S3 {
s3Config := defaultStorage.GetS3Config()
if s3Config == nil {
return errors.New("storageSetting default storage S3 config is required")
}
for _, field := range []struct {
name string
value string
}{
{name: "accessKeyId", value: s3Config.AccessKeyId},
{name: "accessKeySecret", value: s3Config.AccessKeySecret},
{name: "endpoint", value: s3Config.Endpoint},View on GitHub (pinned to 14d757ce1f)
Solutions
- Provide the S3 config inline: add "s3Config": { "accessKeyId": "...", "accessKeySecret": "...", "endpoint": "...", "region": "...", "bucket": "..." } to storageSetting.
- Or declare the S3 storage under storageSetting.storages[] with a matching id/actived state.
- Or, if local storage is actually intended, set "storageType": "LOCAL".
Example fix
// before
{ "key": "STORAGE", "storageSetting": { "storageType": "S3", "uploadSizeLimitMb": 100 } }
// after
{ "key": "STORAGE", "storageSetting": { "storageType": "S3", "uploadSizeLimitMb": 100,
"s3Config": { "accessKeyId": "AKIA...", "accessKeySecret": "...", "endpoint": "https://s3.amazonaws.com", "region": "us-east-1", "bucket": "memos" } } } Defensive patterns
Strategy: validation
Validate before calling
st := setting.GetStorageSetting()
if st.StorageType == storepb.InstanceStorageSetting_S3 && st.S3Config == nil && len(st.Storages) == 0 {
return errors.New("S3 storageType requires s3Config or storages entries")
} Type guard
func s3StorageIsConfigured(st *storepb.InstanceStorageSetting) bool {
if st.GetStorageType() != storepb.InstanceStorageSetting_S3 {
return true
}
return st.GetS3Config() != nil || len(st.GetStorages()) > 0
} Prevention
- Treat storageType as a commitment: only declare S3 when the full s3Config is mounted in the same file.
- Mount S3 credentials as a separate secret file and reference it in your config generator, so a missing secret fails your pipeline instead of server startup.
When it happens
Trigger: A memos-instance-setting-storage.json with "storageType": "S3" and no "s3Config" block and empty/missing "storages" array; partially migrated S3 config where credentials moved into storages[] but the array got dropped.
Common situations: Declaring intent ("we use S3") before filling in credentials; downgrading from a version that stored S3 config in the database and assuming the server will read it from there; typo in the s3Config key leaving it unset.
Related errors
- storageSetting default storage S3 config is required
- storageSetting must be populated for key STORAGE
- storageSetting.uploadSizeLimitMb must not be negative
- uid is invalid
- name is required
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/44e3e4ec525feaf3.
Report an issue: GitHub.