Thinkmill / Thinkmill/keystatic
saving body-only edit deletes index.json without re-adding it (entryLayout: 'content' + format: {data:'json'})
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.4k
- Forks
- 159
- Avg merge
- 21h 41m
- Merged PRs (30d)
- 2
Description
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
- Open an existing entry in the GitHub-storage-mode admin UI.
- Edit only the markdoc body field (leave title/metadata untouched).
- Click Save.
- Inspect the resulting commit:
index.jsonis deleted,content.mdocis
modified in place — no addition recreatesindex.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.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Inspect useUpsertItem in keystatic-core-ui.js, focusing on how args.initialFiles, additions, filesToDelete, and the cached unscopedTree interact during a body-only save. Reproduce the GitHub-storage edit from the issue and verify that saving unchanged metadata retains index.json while updating content.mdoc, including on a follow-up save.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- content
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100