Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Keystatic Cloud: saving a fields.array entry wipes sibling fields, or fails with a stale-deletion GraphQL error

オープン
#1,627 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 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.6
  • astro: ^5.17.1
  • Storage: Keystatic Cloud (jaywalk/domaineyoyo project)
  • Repo: jaywalkco/domaineyoyo, branch main

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 oid 732e05fa95f81bcf77f04c0fce89107afb47ecd4 — screenshot available, editor toolbar shows "Unsaved" with the red GraphQL error banner.
  • Entry km31, cited oid 5c5daf1c05b8a39a802d5667acf1ef07ea4d578a.

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.image siblings, or with the emptyContent body-field pattern for .md collections?
  • Any recommended mitigation short of removing fields.image/emptyContent from 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 を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

Thinkmill/keystatic のほかの issue

Thinkmill/keystatic の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。