facebook/relay · error

Expected at least one of an @updatable reader AST, or normal

Error message

Expected at least one of an @updatable reader AST, or normalization AST to be present

What it means

generate_artifacts panics when an operation grouping has neither an @updatable reader AST nor a normalization AST. Every grouped operation must produce at least one of these artifacts; an empty group means an earlier compiler stage left inconsistent data.

Source

Thrown at compiler/crates/relay-compiler/src/build_project/generate_artifacts.rs:177

                // Therefore this must be an updatable query in order to continue.
                if reader
                    .directives
                    .named(*UPDATABLE_DIRECTIVE)
                    .is_some()
                {
                    let source_hash = source_hashes
                        .get(&reader.name.item.into())
                        .cloned()
                        .unwrap();
                    return generate_updatable_query_artifact(
                        ArtifactSourceKey::ExecutableDefinition(reader.name.item.into()),
                        project_config,
                        &operations,
                        source_hash,
                    )
                }
            }
            panic!("Expected at least one of an @updatable reader AST, or normalization AST to be present");
        })
        .chain(programs.reader.fragments().map(|reader_fragment| {
            let source_name = if let Some(client_edges_directive) =
                ClientEdgeGeneratedQueryMetadataDirective::find(&reader_fragment.directives)
            {
                client_edges_directive.source_name.item
            } else {
                reader_fragment.name.item.into()
            };
            // If the fragment is generated for the RelayResolver model (id, or model instance)
            // we need to update the source definition to include the original text of the resolver.
            let source_hash = source_hashes.get(&source_name).cloned();

            // We need this `if/else` here because of the way the compiler is handling the aritfacts
            // deletion (see commit_project in compiler.rs).
            // To remove the artifact, the artifact map should not contain any document/source that may
            // generate the artifact. If we merge these sources (fragment name and resolver hash)
            // then the removal of the source hash won't trigger the removal of the artifact, because

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Delete generated artifacts/compiler cache and rerun the compiler
  2. Reduce the offending operation to a minimal repro and check which directives (@updatable etc.) it uses
  3. Pin/report against the Relay version — this panic usually indicates a compiler bug
Defensive patterns

Strategy: try-catch

Validate before calling

// Wrap compiler invocation in a process-level guard and retry a clean build
// Node wrapper example:
const { spawnSync } = require('child_process');
const r = spawnSync('relay-compiler', ['--watchman', 'false'], { stdio: 'inherit' });
if (r.status !== 0) {
  require('fs').rmSync('__generated__', { recursive: true, force: true });
  spawnSync('relay-compiler', [], { stdio: 'inherit' });
}

Try / catch

try {
  runRelayCompiler();
} catch (e) {
  if (/reader AST, or normalization AST/.test(String(e))) {
    cleanCachesAndRetry(); // report upstream if reproducible
  } else throw e;
}

Prevention

When it happens

Trigger: During artifact generation, a grouped operation (in the match arm before this panic) matches no known artifact kind, so neither reader nor normalization AST exists for it.

Common situations: Compiler bug or partially-compiled operation (e.g. an @updatable query missing normalization output) after a Relay upgrade; inconsistent compiler state from an interrupted run.

Related errors


AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02). Data as JSON: /api/errors/d0c6436f6f1ed198. Report an issue: GitHub.