usememos/memos · error
attachment storage is not configured
Error message
attachment storage is not configured
What it means
ResolveStorage (store/storage.go:212) walks a fallback chain to find the storage backend for an attachment: explicit storageID lookup in the instance setting, then the attachment's legacy S3 config, then the instance-level legacy S3 config. Reaching line 246 means storageID was empty AND no S3 config existed anywhere, so no driver can serve the attachment — errors.New("attachment storage is not configured"). Contrast with line 244, which fires when a non-empty storageID is simply absent from the setting.
Source
Thrown at store/storage.go:246
s3Config = setting.GetS3Config()
}
if s3Config != nil {
// Prefer the configured storage addressing the same namespace so legacy
// attachments pick up rotated credentials and transport options.
legacyStorage := &storepb.Storage{
Type: storepb.StorageType_STORAGE_TYPE_S3,
Config: &storepb.Storage_S3Config{S3Config: s3Config},
}
if configuredStorage := findEquivalentStorage(setting.GetStorages(), legacyStorage); configuredStorage != nil {
return configuredStorage, nil
}
return legacyStorage, nil
}
if storageID != "" {
return nil, errors.Errorf("storage %q is not configured", storageID)
}
return nil, errors.New("attachment storage is not configured")
}
// ResolveStorageDriver resolves the configured storage referenced by an attachment
// and returns its driver. legacyS3Config supports attachments written before
// storage IDs were introduced.
func ResolveStorageDriver(
ctx context.Context,
setting *storepb.InstanceStorageSetting,
storageID string,
legacyS3Config *storepb.StorageS3Config,
) (storage.Driver, error) {
resolvedStorage, err := ResolveStorage(setting, storageID, legacyS3Config)
if err != nil {
return nil, err
}
return storage.NewDriver(ctx, resolvedStorage)
}
View on GitHub (pinned to 14d757ce1f)
Solutions
- Configure an instance storage setting with at least one storage (a LOCAL type entry is enough) via the workspace setting API or admin UI, so attachments without an explicit storage ID resolve to the default.
- If the attachments were originally S3-backed, restore the legacy S3 config (workspace-level S3 setting) or add an S3 storage entry addressing the same bucket so findEquivalentStorage matches it and rotated credentials are picked up.
- Check the attachment row: if it should point at a specific storage, set its storage_id to a configured storage ID.
- Restore the workspace setting from a backup taken before the configuration was lost rather than re-creating storages with new IDs.
Example fix
// before: instance setting has no storages, attachment has no storage_id stor, err := store.ResolveStorage(setting, att.StorageId, att.S3Config) // error // after: ensure a default LOCAL storage exists before resolving store.NormalizeInstanceStorageSetting(setting) // appends LOCAL fallback if empty stor, err := store.ResolveStorage(setting, att.StorageId, att.S3Config)
Defensive patterns
Strategy: fallback
Validate before calling
// Before resolving an attachment's driver, ensure the instance can serve it:
func canResolveStorage(setting *storepb.InstanceStorageSetting, att *storepb.Attachment) bool {
if att.GetStorageId() != "" && store.FindStorage(setting, att.GetStorageId()) != nil {
return true
}
return att.GetS3Config() != nil || setting.GetS3Config() != nil || len(setting.GetStorages()) > 0
} Try / catch
stor, err := store.ResolveStorage(setting, att.StorageId, att.S3Config)
if err != nil {
if strings.Contains(err.Error(), "storage is not configured") {
// surface a configuration action to the admin: set up an instance
// storage (LOCAL or S3) before attachments can be served
}
return err
} Prevention
- Back up the workspace storage setting together with the database before migrations or instance moves.
- Keep at least one LOCAL storage entry in the instance setting as a permanent fallback.
- When re-creating S3 storages, reuse the original bucket/endpoint so findEquivalentStorage matches legacy attachments.
- Set explicit storage IDs on attachments when migrating off the legacy S3 config.
When it happens
Trigger: Reading/downloading an attachment that has no storage_id and no legacy S3 config (i.e. it was expected to be LOCAL) while the instance storage setting contains no usable local entry; the instance setting was wiped, replaced by a config-file deployment, or restored from a backup that dropped storage configuration.
Common situations: Migrating a database between instances without copying workspace storage settings; rolling back to a config-file-based S3 setup after using the storage registry; a fresh install pointing at an old database; manually editing the workspace_setting row and losing the storages list.
Related errors
- storageSetting.s3Config is required for S3
- storageSetting default storage S3 config is required
- default storage is not configured
- storageSetting must be populated for key STORAGE
- storageSetting.uploadSizeLimitMb must not be negative
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/d93a2a14b30c5eb2.
Report an issue: GitHub.