{"record":{"id":"7e8b11cd7969753c","repo":"usememos/memos","slug":"storagesetting-default-storage-s3-config-is-requir","errorCode":null,"errorMessage":"storageSetting default storage S3 config is required","messagePattern":"storageSetting default storage S3 config is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"store/deployment_config.go","lineNumber":249,"sourceCode":"\tcase storepb.InstanceSettingKey_STORAGE:\n\t\tstorage := setting.GetStorageSetting()\n\t\tif storage == nil {\n\t\t\treturn errors.New(\"storageSetting must be populated for key STORAGE\")\n\t\t}\n\t\t// Normalization would silently self-heal this misconfiguration to LOCAL;\n\t\t// a deployment file declaring S3 without a config should fail loudly.\n\t\tif storage.StorageType == storepb.InstanceStorageSetting_S3 && storage.S3Config == nil && len(storage.Storages) == 0 {\n\t\t\treturn errors.New(\"storageSetting.s3Config is required for S3\")\n\t\t}\n\t\tNormalizeInstanceStorageSetting(storage)\n\t\tif storage.UploadSizeLimitMb < 0 {\n\t\t\treturn errors.New(\"storageSetting.uploadSizeLimitMb must not be negative\")\n\t\t}\n\t\tdefaultStorage := GetDefaultStorage(storage)\n\t\tif defaultStorage != nil && defaultStorage.Type == storepb.StorageType_STORAGE_TYPE_S3 {\n\t\t\ts3Config := defaultStorage.GetS3Config()\n\t\t\tif s3Config == nil {\n\t\t\t\treturn errors.New(\"storageSetting default storage S3 config is required\")\n\t\t\t}\n\t\t\tfor _, field := range []struct {\n\t\t\t\tname  string\n\t\t\t\tvalue string\n\t\t\t}{\n\t\t\t\t{name: \"accessKeyId\", value: s3Config.AccessKeyId},\n\t\t\t\t{name: \"accessKeySecret\", value: s3Config.AccessKeySecret},\n\t\t\t\t{name: \"endpoint\", value: s3Config.Endpoint},\n\t\t\t\t{name: \"region\", value: s3Config.Region},\n\t\t\t\t{name: \"bucket\", value: s3Config.Bucket},\n\t\t\t} {\n\t\t\t\tif strings.TrimSpace(field.value) == \"\" {\n\t\t\t\t\treturn errors.Errorf(\"storageSetting default S3 config.%s is required\", field.name)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase storepb.InstanceSettingKey_MEMO_RELATED:\n\t\tif setting.GetMemoRelatedSetting() == nil {","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/store/deployment_config.go#L231-L267","documentation":"Thrown when the resolved default storage in a STORAGE instance-setting file has type S3 but its embedded s3Config message is nil. GetDefaultStorage(storage) picks the active/default storage (either the legacy top-level s3Config or a storages[] entry); when that storage says S3 but carries no config object, validation fails rather than letting uploads hit a nil config at runtime.","triggerScenarios":"storageSetting.storages[] contains an entry with \"type\": \"S3\" marked active/default but the entry lacks its \"s3Config\" block; or the storages[] entry has a typo'd config key so protojson leaves it unset.","commonSituations":"Multi-storage setups migrated from the database where the s3Config nesting level changed; writing storages[] entries by hand and omitting the config; secret-mounting the credentials separately so the JSON has an empty object.","solutions":["Add the full \"s3Config\" object inside the S3 storages[] entry (accessKeyId, accessKeySecret, endpoint, region, bucket).","Verify the default/active storage selection: if the default should be LOCAL, fix the actived flags or storageType so the S3 entry is not the default."],"exampleFix":"// before\n\"storages\": [ { \"id\": 1, \"name\": \"s3\", \"type\": \"S3\", \"actived\": true } ]\n\n// after\n\"storages\": [ { \"id\": 1, \"name\": \"s3\", \"type\": \"S3\", \"actived\": true,\n  \"s3Config\": { \"accessKeyId\": \"AKIA...\", \"accessKeySecret\": \"...\", \"endpoint\": \"https://s3.amazonaws.com\", \"region\": \"us-east-1\", \"bucket\": \"memos\" } } ]","handlingStrategy":"validation","validationCode":"def := store.GetDefaultStorage(st)\nif def != nil && def.Type == storepb.StorageType_STORAGE_TYPE_S3 && def.GetS3Config() == nil {\n    return errors.New(\"default S3 storage entry is missing its s3Config\")\n}","typeGuard":"func defaultStorageIsComplete(st *storepb.InstanceStorageSetting) bool {\n    def := store.GetDefaultStorage(st)\n    if def == nil || def.GetType() != storepb.StorageType_STORAGE_TYPE_S3 {\n        return true\n    }\n    return def.GetS3Config() != nil\n}","tryCatchPattern":null,"preventionTips":["When multiple storages[] entries exist, double-check which one is marked active/default and that it carries its config.","Regression-test multi-storage deployment files with a config dry-run before rolling out."],"tags":["configuration","validation","storage","s3","startup"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}