usememos/memos · error

storage setting is required

Error message

storage setting is required

What it means

PrepareInstanceStorageSettingUpdate (store/storage.go:88) normalizes and validates an incoming InstanceStorageSetting for a workspace/instance update; a nil incoming setting is a protocol-level mistake, so it fails fast with errors.New("storage setting is required") at line 90. The function then adopts preserved storages, validates IDs/types/S3 configs, and re-identifies storages whose physical namespace changed — none of which is meaningful without a setting object.

Source

Thrown at store/storage.go:90

	if FindStorage(setting, setting.DefaultStorageId) == nil {
		fallback := builtinStorage(storepb.StorageType_STORAGE_TYPE_LOCAL)
		if len(setting.Storages) > 0 {
			fallback = setting.Storages[0]
		} else {
			setting.Storages = append(setting.Storages, fallback)
		}
		setting.DefaultStorageId = fallback.Id
	}
	moveDefaultStorageFirst(setting)

	synchronizeLegacyStorageFields(setting)
}

// PrepareInstanceStorageSettingUpdate preserves storages still referenced by
// existing attachments and assigns a new identity when a physical namespace changes.
func PrepareInstanceStorageSettingUpdate(incoming, existing *storepb.InstanceStorageSetting) error {
	if incoming == nil {
		return errors.New("storage setting is required")
	}

	if existing != nil {
		NormalizeInstanceStorageSetting(existing)
	}
	// A request may reference a storage the server preserves without resending
	// it; adopt the stored entry so the reference survives validation and
	// normalization instead of being silently replaced by a fallback default.
	if incoming.DefaultStorageId != "" && FindStorage(incoming, incoming.DefaultStorageId) == nil {
		preserved := FindStorage(existing, incoming.DefaultStorageId)
		if preserved == nil {
			return errors.Errorf("default storage %q is not configured", incoming.DefaultStorageId)
		}
		incoming.Storages = append(incoming.Storages, proto.CloneOf(preserved))
	}

	legacyRequest := len(incoming.Storages) == 0
	if !legacyRequest {

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Always populate the storage_setting field in the UpdateWorkspaceSetting/instance-setting request, even when only its sub-fields change.
  2. Guard the call site: only invoke the prepare function when the incoming setting is non-nil, and skip the storage-branch otherwise.
  3. After upgrading memos, regenerate client stubs so an omitted storage_setting is distinguishable from an empty one.

Example fix

// before
setting := req.GetSetting().GetStorageSetting() // nil when field omitted
if err := store.PrepareInstanceStorageSettingUpdate(setting, existing); err != nil { return err }

// after
setting := req.GetSetting().GetStorageSetting()
if setting == nil {
    return status.Errorf(codes.InvalidArgument, "storage setting is required")
}
if err := store.PrepareInstanceStorageSettingUpdate(setting, existing); err != nil { return err }
Defensive patterns

Strategy: type-guard

Validate before calling

if req.GetSetting().GetStorageSetting() == nil {
    return status.Errorf(codes.InvalidArgument, "storage setting is required")
}
// only then:
err := store.PrepareInstanceStorageSettingUpdate(req.GetSetting().GetStorageSetting(), existing)

Type guard

func hasStorageSetting(req *v1.UpdateWorkspaceSettingRequest) bool {
    return req.GetSetting() != nil && req.GetSetting().GetStorageSetting() != nil
}

Try / catch

if err := store.PrepareInstanceStorageSettingUpdate(incoming, existing); err != nil {
    if err.Error() == "storage setting is required" {
        return status.Errorf(codes.InvalidArgument, "%v", err)
    }
    return status.Errorf(codes.Internal, "failed to prepare storage setting: %v", err)
}

Prevention

When it happens

Trigger: Calling PrepareInstanceStorageSettingUpdate(nil, existing) — e.g. an UpdateInstanceSetting/UpdateWorkspaceSetting handler that extracts the storage setting from the request and the request omitted the storage_setting field, leaving the extracted proto nil.

Common situations: API clients (or older SDK versions) sending a workspace setting update that only touches a non-storage field while the server code unconditionally prepares the storage portion; schema/proto drift after upgrading; hand-rolled integrations constructing the request protobuf incompletely.

Related errors


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