Skip to content

Create the local persisted queries file when it is missing - #5388

Open
GregoryCollett wants to merge 1 commit into
facebook:mainfrom
GregoryCollett:create-missing-persisted-queries-file
Open

Create the local persisted queries file when it is missing#5388
GregoryCollett wants to merge 1 commit into
facebook:mainfrom
GregoryCollett:create-missing-persisted-queries-file

Conversation

@GregoryCollett

Copy link
Copy Markdown

Problem

When persistConfig uses the local file mode, the compiler refuses to start if the configured file does not exist:

The file `./persisted_queries.json` for the local query persisting does not exist. Please, make sure the file path is correct.

But this file is a compiler outputthe docs describe the feature as "you can generate a local JSON file which contains a map of operation_id => full operation text". Because it's a build artifact it is typically gitignored, so the compiler only starts on machines where a previous run happens to have left the file behind. On a fresh checkout — i.e. every CI run — it errors out until you either commit a stub {} map or wrap every compiler invocation in a script that pre-creates the file. (It's the single-file analogue of committing a .gitkeep to satisfy the artifactDirectory check.)

The check also lives inside Deserialize for PersistConfig, so it performs filesystem I/O during config parsing and resolves the path against the process cwd rather than the config file's location.

Changes

  1. PersistConfig deserialization no longer requires the local file to exist (and no longer touches the filesystem).
  2. LocalPersister::new treats a missing file as an empty query map (the first-run state). Other read errors still panic, but the message now includes the underlying io error instead of claiming the file must exist.
  3. LocalPersister::finalize creates missing parent directories before writing, matching what the artifact writer does for artifacts.
  4. Doc comment on PersistConfig::Local updated accordingly and relay-compiler-config-schema.json regenerated.

Behaviour notes

  • Existing setups are unaffected: when the file exists, its entries are still loaded and merged exactly as before. This is pinned by the persisted_queries_file_existing_entries_preserved fixture, whose snapshot is byte-identical with and without the code change.
  • A typo'd file path now results in the map being written at the typo'd path instead of a startup error — i.e. ordinary build-output (mkdir -p) semantics.
  • Unchanged, but worth stating: operations whose generated artifacts are already up to date are not re-persisted (their ids are extracted from the artifacts), so deleting only the map file while keeping artifacts yields a map without those entries. --repersist already exists to force a full re-persist. That outcome is identical to today's stub-file workaround; this PR just removes the need for the workaround.

Tests

Three new integration fixtures:

  • persisted_queries_file_created_when_missing — the main repro. Before the fix this snapshotted the startup error; now the compiler runs and the snapshot shows persisted_queries.json being created alongside the artifact.
  • persisted_queries_file_existing_entries_preserved — pins the pre-existing merge behaviour (snapshot unchanged by the fix).
  • persisted_queries_file_missing_parent_directories_created"file": "./persisted/queries.json" with no persisted/ directory in the fixture.

cargo test --locked for the workspace passes locally apart from server_daemon::tests::test_status_stale_when_socket_file_exists_but_no_listener, which on my machine fails under the parallel lib test run and passes in isolation, both with and without this change (pre-existing, unrelated).

Also verified end-to-end against our application's single-project relay.config.json with the persist file absent: previously failed at startup, now compiles and writes the populated map.

With `persistConfig.file`, the compiler previously refused to start if
the file did not exist ("The file `...` for the local query persisting
does not exist"), even though the file is a compiler output. On fresh
checkouts and in CI the file never exists, forcing projects to commit a
stub map or wrap the compiler in a script that pre-creates one.

- PersistConfig deserialization no longer requires the file to exist
  (this also removes filesystem access from Deserialize, which resolved
  the path against the process cwd rather than the config location).
- LocalPersister::new treats a missing file as an empty query map;
  other read errors now surface the underlying io error.
- LocalPersister::finalize creates missing parent directories, the same
  way the artifact writer does for artifacts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed label Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant