Keystatic Cloud: saving a fields.array entry wipes sibling fields, or fails with a stale-deletion GraphQL error
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 48/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- graphql, typescript
調査の方向性
Start by reproducing the reported schema with a fields.array entry alongside fields.image fields and an emptyContent body, then inspect the generated commit diff and GraphQL deletion request. Done means saving an array-only edit preserves sibling image fields and body content and does not produce a stale-deletion error.
索引モデルが issue の本文から書いたものです。
説明
Keystatic Cloud: saving a fields.array entry either wipes sibling fields or fails with a stale-deletion GraphQL error
Environment
@keystatic/core: ^0.5.48@keystatic/astro: ^5.0.6astro: ^5.17.1- Storage: Keystatic Cloud (
jaywalk/domaineyoyoproject) - Repo:
jaywalkco/domaineyoyo, branchmain
Schema (relevant fields)
wines: collection({
label: 'Vins',
slugField: 'name',
path: 'src/content/wines/*',
format: { contentField: 'body' },
schema: {
name: fields.slug({ name: { label: 'Nom du vin' } }),
category: fields.select({ /* ... */ }),
subtitle: fields.text({ label: 'Sous-titre' }),
description: fields.text({ label: 'Description courte', multiline: true }),
imageFeatured: fields.image({
label: 'Image homepage (étiquette cadrée)',
directory: 'public/images/wines',
publicPath: '/images/wines/',
}),
imageDetail: fields.image({
label: 'Image détail (étiquette complète)',
directory: 'public/images/wines',
publicPath: '/images/wines/',
}),
technicalSheets: fields.array(
fields.object({
label: fields.text({ label: 'Libellé' }),
fileRef: fields.text({ label: 'Lien du fichier PDF' }),
}),
{ label: 'Fiches techniques', itemLabel: (props) => props.fields.label.value || 'Fiche' }
),
order: fields.integer({ label: "Ordre d'affichage", defaultValue: 0 }),
body: (fields as any).emptyContent({ extension: 'md' }),
},
}),
Note technicalSheets contains no fields.image/fields.file — it's a plain array of two text fields.
Symptom A — silent field loss on save (no error shown)
Editing an entry's technicalSheets array (adding one new {label, fileRef} item) and saving produced a commit where, in addition to the intended array change, imageFeatured, imageDetail, and the entire markdown body were dropped from the file, with no error surfaced in the editor UI.
Commit: e9dae84991f2cae5590201942b5b3561fa501ee6 (keystatic-cloud[bot], co-authored by the connected GitHub account).
Diff (trimmed):
name: "Louve Noire"
category: "alberes"
subtitle: "Vin de France Millésimé Albères"
description: "Cuvée parcellaire multi-cépages. Vigne de 20 à 80 ans."
-imageFeatured: "/images/wines/louve.avif"
-imageDetail: "/images/wines/louve.avif"
labelArtist: "Sarah Fatmi"
...
technicalSheets:
- label: "Fiche technique Louve Noire 2021"
fileRef: "/fiches/Fiche-technique-Louve-Noire-2021.pdf"
...
+ - label: 'Fiche technique Louve Noire 2025 '
+ fileRef: /fiches/LOUVE-NOIRE-2025.pdf
order: 5
---
-
-Parcelle de 50 ares sur le Piémont des Albères.
-
-Multi-cépages Catalogne / Sud-Ouest : ...
-
-Cuvée parcellaire.
-
-Age de la vigne compris entre 20 et 80 ans.
imageFeatured/imageDetail were untouched by the editing session (the user only opened the "Fiches techniques" array and added one item), yet both keys and the body content were gone from the resulting commit.
Symptom B — save rejected with a stale-deletion GraphQL error
On two separate, unrelated entries, the same action (adding one technicalSheets item, pasting a value into fileRef, then Save) instead failed outright with:
[GraphQL] A path was requested for deletion which does not exist as of commit oid `<current HEAD>`
Both times the cited commit oid was confirmed to be the actual, current main HEAD at that moment (not a stale client cache — verified against the GitHub API directly), and both were on freshly loaded editor sessions (page opened new, not a long-lived tab). No commit was created (save cleanly rejected), so no data was lost in these two instances, unlike Symptom A.
Occurrences:
- Entry
alma, cited oid732e05fa95f81bcf77f04c0fce89107afb47ecd4— screenshot available, editor toolbar shows "Unsaved" with the red GraphQL error banner. - Entry
km31, cited oid5c5daf1c05b8a39a802d5667acf1ef07ea4d578a.
Working theory
Some external context: the same day, several commits were pushed to main directly via the GitHub Contents API (bypassing the Keystatic Cloud editor entirely — a custom upload tool, unrelated automation), including renames of a few files referenced by fields.image values in other entries. It's possible Keystatic Cloud keeps a server-side index/cache of blobs per document that gets invalidated or desynced by external pushes, and that on the next editor save it attempts to reconcile a stale reference — either deleting fields it can't find a current blob for (Symptom A, silently dropping keys rather than erroring), or rejecting the whole mutation when the path really is gone (Symptom B).
That said, Symptom A's very first occurrence (Louve Noire) happened on an entry that had not been touched by any external push beforehand, so the external-push theory doesn't fully explain it on its own. It's possible the two symptoms share a root cause purely in how a fields.array save re-serializes the whole document (per #1625's description of full-document re-serialization on every save) and interacts with fields.image state that the editor hasn't freshly hydrated.
Impact
Symptom A is the serious one: a normal, unremarkable content edit (adding a PDF link to a list) silently destroyed unrelated fields with zero indication to the editor that anything but the intended change had happened. We only caught it because we happened to be auditing the repo for something else the same day.
What we'd like to know
- Is this a known issue with
fields.array+fields.imagesiblings, or with theemptyContentbody-field pattern for.mdcollections? - Any recommended mitigation short of removing
fields.image/emptyContentfrom the schema?
We're happy to provide repo access or more repro detail if useful.
- 主要言語
- TypeScript
- スター
- 2.5k
- フォーク
- 176
- 平均マージ
- 5時間 46分
- マージ済み PR(30日)
- 3
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
Thinkmill/keystatic のほかの issue
-
Incorrect Dutch translations: “Save” is translated as “Redden”対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
Typo/Grammar on Website Homepage対応中かも @Punith1117 が 148 日前に担当しました。 オープン
難易度 1/5 1時間未満 初心者へのやさしさ 85/100
メンテナーはふだん 1 日以内に返信
-
Array field: no visible edit button on rows and no close button in the "Edit item" dialog対応中かも @bacarndiaye が 9 日前に担当しました。 オープン
難易度 3/5 半日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
-
Feature: post-save "publishing" notice / `onCommit` hook so editors know changes aren't live yetオープン
難易度 4/5 3〜5日 初心者へのやさしさ 52/100
メンテナーはふだん 1 日以内に返信
Thinkmill/keystatic の issue をすべて見る
似ている issue
-
e2e-failure ready-to-code
難易度 1/5 1時間未満 初心者へのやさしさ 82/100
redhat-developer/rhdh-plugin-export-overlays#4616 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
メンテナーはふだん 1 日以内に返信
-
ai-handle
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
nextlevelbuilder/dewee-web-v2#73 ·
メンテナーはふだん 1 日以内に返信
-
backend bug good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
PoCInnovation/Distribox#255 ·
メンテナーはふだん 1 日以内に返信