Skip to content

Discard oversized non-file paste items to prevent huge database rows #4698

Description

@guiyanakuang

Background

A production crash on mobile was root-caused to single paste rows larger than 10MB (Android requery CursorWindow limitation; the read side has already been fixed in the mobile repos). The main source of such rows is copying very large text on desktop, which then syncs to mobile.

This adds a write-side defense shared across all three platforms via commonMain: oversized non-file paste content is discarded before it is persisted.

Scope

The limit applies only to non-file carrier types (text / HTML / RTF / URL / color). Files and images store their payload on disk and remain governed by the existing sync file size limit. Naming, config keys, and settings copy all say "non-file" explicitly to avoid implying that all pastes are limited.

  • New config: enabledNonFilePasteSizeLimit (default true) and maxNonFilePasteSize (MB, default 8), following the enabledSyncFileSizeLimit/maxSyncFileSize style.
  • New commonMain process plugin DiscardOversizedNonFilePlugin, registered right after RemoveInvalidPlugin: oversized non-file items are filtered out (silent flavor degradation, log only); when every item is discarded, one notification is shown and the existing empty-list path mark-deletes the paste row.
  • Remote receive path (releaseRemotePasteData) bypasses the plugin pipeline, so it gets a dedicated pre-persist check: any oversized non-file item skips the whole paste (flavor degradation would break hash/content consistency used by same-hash dedup) and notifies with the source device name. The sender keeps the full data, so nothing is lost.
  • Desktop settings UI: switch + size counter next to the sync file size limit, with copy that spells out the affected types and the file/image exemption.
  • i18n keys added to all 10 languages.

Out of scope

  • No sender-side skip and no spilling large text to file storage (possible future work).
  • Mobile follow-up (config implementations, DI registration, settings UI) happens in the mobile repos after this lands.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions