usememos/memos · error

storage ID is required

Error message

storage ID is required

What it means

validateInstanceStorages (store/storage.go:464) checks each entry of setting.Storages during a storage-setting update; an entry that is nil or has an empty Id fails with errors.New("storage ID is required"). Storage IDs are the stable identity used by DefaultStorageId, attachment references, and namespace-change re-identification, so an ID-less entry would break resolution. NormalizeInstanceStorageSetting normally guarantees IDs, which is why only raw canonical update requests are validated explicitly (storage.go:107-115).

Source

Thrown at store/storage.go:465

		setting.S3Config = proto.CloneOf(storage.GetS3Config())
		return
	}
	// Keep the most recently configured S3 storage available to legacy
	// attachments that predate both storage IDs and embedded configurations.
	for _, configuredStorage := range setting.Storages {
		if configuredStorage.GetS3Config() != nil {
			setting.S3Config = proto.CloneOf(configuredStorage.GetS3Config())
			return
		}
	}
	setting.S3Config = nil
}

func validateInstanceStorages(setting *storepb.InstanceStorageSetting) error {
	seenIDs := map[string]bool{}
	for _, storage := range setting.Storages {
		if storage == nil || storage.Id == "" {
			return errors.New("storage ID is required")
		}
		if seenIDs[storage.Id] {
			return errors.Errorf("duplicate storage ID %q", storage.Id)
		}
		seenIDs[storage.Id] = true
		if storage.Type == storepb.StorageType_STORAGE_TYPE_UNSPECIFIED {
			return errors.Errorf("storage %q type is required", storage.Id)
		}
		if storage.Type == storepb.StorageType_STORAGE_TYPE_S3 && storage.GetS3Config() == nil {
			return errors.Errorf("storage %q S3 config is required", storage.Id)
		}
	}
	if !seenIDs[setting.DefaultStorageId] {
		return errors.Errorf("default storage %q is not configured", setting.DefaultStorageId)
	}
	return nil
}

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Give every storages[] entry a non-empty id (e.g. "s3-primary", "local") before sending the update; keep IDs stable across edits so attachments keep resolving.
  2. Send the canonical update path (storages list populated) rather than relying on legacy normalization, and validate IDs client-side first.
  3. After upgrading the server, re-fetch the current setting and echo its storage IDs back instead of constructing them from scratch.

Example fix

// before
setting.Storages = append(setting.Storages, &storepb.Storage{
    Type:   storepb.StorageType_STORAGE_TYPE_S3,
    Config: &storepb.Storage_S3Config{S3Config: cfg}, // no Id
})

// after
setting.Storages = append(setting.Storages, &storepb.Storage{
    Id:     "s3-primary",
    Type:   storepb.StorageType_STORAGE_TYPE_S3,
    Config: &storepb.Storage_S3Config{S3Config: cfg},
})
Defensive patterns

Strategy: validation

Validate before calling

func validStorages(setting *storepb.InstanceStorageSetting) error {
    seen := map[string]bool{}
    for _, s := range setting.GetStorages() {
        if s == nil || s.GetId() == "" {
            return errors.New("storage ID is required")
        }
        if seen[s.GetId()] {
            return errors.Errorf("duplicate storage ID %q", s.GetId())
        }
        seen[s.GetId()] = true
    }
    return nil
}
// run before PrepareInstanceStorageSettingUpdate / the update request

Type guard

func hasAllStorageIDs(setting *storepb.InstanceStorageSetting) bool {
    for _, s := range setting.GetStorages() {
        if s == nil || s.GetId() == "" {
            return false
        }
    }
    return true
}

Prevention

When it happens

Trigger: Sending an UpdateWorkspaceSetting storage request whose storages[] includes a message with no id field (empty string) or a null list element; constructing an InstanceStorageSetting programmatically and appending an unconfigured &storepb.Storage{}.

Common situations: Clients that omit id assuming the server generates one; hand-built protobuf/JSON payloads from scripts or Terraform-like tooling; partial request snapshots replayed after a proto schema change renamed the id field; older client versions unaware that named storages require explicit IDs.

Related errors


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/74867d4a4abfaa15. Report an issue: GitHub.