facebook/relay · error
Expected Condition with static value to have been pruned or
Error message
Expected Condition with static value to have been pruned or inlined.
What it means
Relay's codegen builder converts an @include/@skip directive condition into a serialized Primitive for the generated AST. By this point in the pipeline, any Condition whose value is a compile-time constant must have already been pruned (directive statically false) or inlined into the selection (statically true) by earlier normalization passes. Hitting Constant means a condition with a static value survived into key building, which the compiler considers a bug in earlier passes or an unsupported directive placement.
Source
Thrown at compiler/crates/relay-codegen/src/build_ast.rs:2471
aliased_fragment
}
} else {
primitive
}
}
}
}
fn build_condition(
&mut self,
context: &mut ContextualMetadata,
condition: &Condition,
) -> Primitive {
let selections = self.build_selections(context, condition.selections.iter());
Primitive::Key(self.object(object! {
condition: Primitive::String(match &condition.value {
ConditionValue::Variable(variable) => variable.name.item.0,
ConditionValue::Constant(_) => panic!(
"Expected Condition with static value to have been pruned or inlined."
),
}),
kind: Primitive::String(CODEGEN_CONSTANTS.condition_value),
passing_value: Primitive::Bool(condition.passing_value),
selections: selections,
}))
}
pub fn build_operation_variable_definitions(
&mut self,
variable_definitions: &[VariableDefinition],
) -> AstKey {
let var_defs = variable_definitions
.iter()
.map(|def| {
let default_value = if let Some(const_val) = &def.default_value {
self.build_constant_value(&const_val.item)View on GitHub (pinned to 668b1b85e0)
Solutions
- Replace static @skip/@include arguments with a variable, e.g. `field @skip(if: $shouldSkip)`, and pass the variable at runtime
- Remove the statically-valued @skip/@include directive entirely and add/remove the field in the document (or use `@required`/fragment composition) as appropriate
- Update the Relay Compiler so constant conditions are pruned/inlined; if using a custom pass, ensure it runs normalization that simplifies constant conditions before codegen
- If it appears to be a compiler bug (variable was intended), file a reduced reproduction against relay compiler
Example fix
// before
query { user { name @skip(if: false) email @include(if: true) } }
// after
query($showEmail: Boolean!) { user { name email @include(if: $showEmail) } } Defensive patterns
Strategy: validation
Validate before calling
// Before compiling, scan documents for static directive args:
function hasStaticSkipInclude(doc) {
const bad = [];
visit(doc, {
Directive(node) {
if ((node.name.value === 'skip' || node.name.value === 'include') &&
node.arguments?.some(a => a.value.kind !== 'Variable')) {
bad.push(node.name.value);
}
}
});
return bad.length === 0;
}
if (!hasStaticSkipInclude(queryDoc)) throw new Error('Use variables with @skip/@include'); Type guard
function isVariableCondition(value) {
return typeof value === 'object' && value !== null && 'variableName' in value;
} Try / catch
try {
compiled = compile(queryText);
} catch (e) {
if (String(e).includes('pruned or inlined')) {
// rewrite static @skip/@include to variables and retry
}
throw e;
} Prevention
- Always pass @skip/@include conditions via GraphQL variables, never literals
- Run a document lint that rejects literal @skip/@include args in CI
- Keep the Relay compiler up to date so pruning/normalization runs
- Test hand-written documents through the compiler pipeline before shipping
When it happens
Trigger: Building the primitive for a @skip or @include directive whose `if:` argument is a literal (e.g. `@skip(if: true)` or `@skip(if: false)`) instead of a variable; a compiler pass that failed to prune/inline such conditions before build_primitive_for_key runs.
Common situations: Hand-written GraphQL documents using static @skip/@include arguments; older or patched compiler pipelines where pruning/normalization was skipped or a new pass inserted conditions without simplifying constants; test fixtures with literal directive args.
Related errors
- @module fragments should be named 'FragmentName_propName', g
- The {} argument in exec_time_resolvers directive should be t
- Unexpected RelayResolverMetadata on inline fragment while ge
- Unexpected parent type for resolver.
- Expected at most one handle directive, got `{handle_field_di
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/8c0aedbeadbac4b9.
Report an issue: GitHub.