facebook/relay · error

unexpected value for @stream if argument: {other:?}

Error message

unexpected value for @stream if argument: {other:?}

What it means

This panic fires during codegen of a @stream directive. The compiler requires the `if` argument of @stream to be either the constant `true` (default, dropped) or a variable name; any other value shape after earlier transforms is unexpected and indicates an untransformed or malformed @stream argument.

Source

Thrown at compiler/crates/relay-codegen/src/build_ast.rs:2018

                kind: Primitive::String(CODEGEN_CONSTANTS.stream),
                selections: next_selections,
            }),
            CodegenVariant::Normalization => {
                let StreamDirective {
                    if_arg,
                    label_arg,
                    use_customized_batch_arg: _,
                    initial_count_arg: _,
                } = StreamDirective::from(
                    stream,
                    &self.project_config.schema_config.defer_stream_interface,
                );
                let if_variable_name = if_arg.and_then(|arg| match &arg.value.item {
                    // `true` is the default, remove as the AST is typed just as a variable name string
                    // `false` constant values should've been transformed away in skip_unreachable_node
                    Value::Constant(ConstantValue::Boolean(true)) => None,
                    Value::Variable(var) => Some(var.name.item),
                    other => panic!("unexpected value for @stream if argument: {other:?}"),
                });
                let label_name = label_arg.unwrap().value.item.expect_string_literal();
                self.object(object! {
                     if_: Primitive::string_or_null(if_variable_name.map(|variable_name| variable_name.0)),
                     kind: Primitive::String(CODEGEN_CONSTANTS.stream),
                     label: Primitive::String(label_name),
                     selections: next_selections,
                 })
            }
        })
    }

    // This function creates a node that is the UNION of the nodes that would be created for read time resolvers
    // and for exec time resolvers (so runtime has ALL the information it needs to run for both resolver modes.)
    // For C2C (client-to-client) edges, we emit ClientEdgeToClientObject with model resolvers.
    // For C2S (client-to-server) edges, we emit ClientEdgeToServerObject with the operation reference.
    fn build_client_edge_exec_and_read_time(
        &mut self,

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Use `@stream` without `if` for unconditional streaming, or `@stream(if: $variable)` with a Boolean variable.
  2. Verify skip_unreachable_node and related transforms execute before build_ast; upgrade/align relay compiler versions across your toolchain.
  3. Add validation to reject constant `if` values on @stream at document-validation time.
  4. Fix any custom codegen or template tooling to emit variable-based `if` arguments only.

Example fix

// before
fragment F on User @stream(if: false) { friends { name } }

// after
fragment F on User @stream(if: $shouldStream) { friends { name } }
Defensive patterns

Strategy: validation

Validate before calling

function validateStreamIf(doc) {
  visit(doc, {
    Directive(node) {
      if (node.name.value === 'stream') {
        const ifArg = node.arguments.find(a => a.name.value === 'if');
        if (ifArg && ifArg.value.kind !== 'Variable' &&
            !(ifArg.value.kind === 'BooleanValue' && ifArg.value.value === true)) {
          throw new Error('@stream if must be a variable or omitted');
        }
      }
    }
  });
}

Type guard

function isValidStreamIf(value) {
  return value == null ||
    (value.kind === 'Variable') ||
    (value.kind === 'BooleanValue' && value.value === true);
}

Try / catch

try {
  relayCompiler.compileAll();
} catch (e) {
  if (String(e).includes('unexpected value for @stream if argument')) {
    console.error('Fix @stream(if:...) usage:', e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Compiling a document with `@stream(if: false)` (constant false should have been removed by skip_unreachable_node) or with a non-variable/non-boolean `if` argument (string, enum, object literal).

Common situations: Feeding raw documents with literal `@stream(if: false)` to the compiler; mismatched compiler version where the constant-condition transform no longer runs; code generators emitting @stream with hardcoded if values.

Related errors


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