Skip to content

saving body-only edit deletes index.json without re-adding it (entryLayout: 'content' + format: {data:'json'}) #1617

Description

@DuvNguyen

Description

When saving an entry that uses entryLayout: 'content' with format: { data: 'json' }
(metadata in index.json, body in a separate content.mdoc/markdown file), editing
only the body content sometimes causes Keystatic to emit a Git commit that
deletes index.json without re-adding it, even though the metadata itself was
unchanged. Content.mdoc updates correctly; index.json is just gone.

Environment

  • @keystatic/core: 0.6.9
  • @keystatic/astro: 6.0.0
  • Storage: kind: 'github'
  • Collection: path: 'src/content/blog/*/', entryLayout: 'content', format: { data: 'json' }

Reproduction

  1. Open an existing entry in the GitHub-storage-mode admin UI.
  2. Edit only the markdoc body field (leave title/metadata untouched).
  3. Click Save.
  4. Inspect the resulting commit: index.json is deleted, content.mdoc is
    modified in place — no addition recreates index.json.

Evidence

Commit example (repo private, redacted path):
content.mdoc | 2 ++
index.json | 24 ----------------------
2 files changed, 2 insertions(+), 24 deletions(-)
delete mode 100644 .../index.json

A follow-up save then fails with:
[GraphQL] A path was requested for deletion which does not exist as of commit oid ''
because index.json was already deleted by the prior save.

Suspected root cause

In useUpsertItem (keystatic-core-ui.js), filesToDelete is derived from
args.initialFiles (a snapshot captured when the entry form was loaded) and
additions is filtered by comparing blob sha against unscopedTree
(a client-side cached tree). If that cached tree is stale relative to the
actual GitHub HEAD (e.g. after a previous save, or a tab left open), an
unchanged file can end up filtered out of additions while still remaining
in filesToDelete, producing a commit with a deletion but no matching
re-addition.

Related

Same symptom as #1269, which was closed without a root cause. This report
includes a concrete reproducible commit diff.

Impact

Data loss — entries silently disappear from the CMS (Entry not found,
0 entries) until manually restored from git history.

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