Skip to content

Plugin storage has no upsert or unique-key constraint, so keyed records can race into duplicates #386

Description

@Mariomarquezt

api.cms.storage exposes only list / create / update / delete (src/core/plugin-sdk/types/serverApi.ts:110-117). createPluginRecord inserts unconditionally (server/repositories/plugins.ts:422-437), and data_json fields carry no uniqueness constraint (migrations-sqlite.ts:358-368, migrations-pg.ts:379-389).

The consequence for any plugin that keys records by a data field — mine stores SEO metadata under key = <tableSlug>:<entryId> — is that two concurrent writers can both miss on read and both insert, leaving two records for one logical key. list ties on created_at are also nondeterministic, so which duplicate wins a later read is not stable.

There is no atomic fix available from inside a plugin.

What I do instead, in case it is useful to anyone hitting this: every read resolves newest-wins for a key and the write paths delete the stale duplicates they find (capped per request); delete removes all matches for the key; and the publish-time filter is strictly read-only, so a render never writes and can never create a duplicate under load. It self-heals, but it is a convention every plugin has to reinvent, and it cannot close the window — only narrow it.

Ask: either

  • collection(id).upsert(data, { uniqueBy: 'field' }), or
  • a declarable unique field on PluginResourceField, so the database enforces it.

Either one turns a race into an error the plugin can handle.

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