facebook/relay · error

unknown @catch `to` value. Use `NULL` or `RESULT` (default)

Error message

unknown @catch `to` value. Use `NULL` or `RESULT` (default) instead.

What it means

CatchTo::from converts the string value of a @catch(to: ...) directive into the CatchTo enum. Only RESULT (default) and NULL are valid; any other string reaches the catch-all arm and panics. This is an internal invariant — the directive's literal values should be validated earlier.

Source

Thrown at compiler/crates/relay-transforms/src/catch_directive.rs:58

pub static CATCH_DIRECTIVE_NAME: LazyLock<DirectiveName> =
    LazyLock::new(|| DirectiveName(intern!("catch")));
pub static NULL_TO: LazyLock<StringKey> = LazyLock::new(|| intern!("NULL"));
pub static RESULT_TO: LazyLock<StringKey> = LazyLock::new(|| intern!("RESULT"));
pub static TO_ARGUMENT: LazyLock<ArgumentName> = LazyLock::new(|| ArgumentName(intern!("to")));

// Possible @catch `to` enum values ordered by severity.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug, Hash)]
pub enum CatchTo {
    Null,
    Result,
}

impl From<StringKey> for CatchTo {
    fn from(to: StringKey) -> Self {
        match to {
            _ if to == *RESULT_TO => Self::Result,
            _ if to == *NULL_TO => Self::Null,
            _ => panic!("unknown @catch `to` value. Use `NULL` or `RESULT` (default) instead."),
        }
    }
}

impl From<CatchTo> for StringKey {
    fn from(val: CatchTo) -> Self {
        match val {
            CatchTo::Null => *NULL_TO,
            CatchTo::Result => *RESULT_TO,
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CatchMetadataDirective {
    pub to: CatchTo,
}
associated_data_impl!(CatchMetadataDirective);

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Change the directive to @catch(to: "NULL") or @catch(to: "RESULT") (or remove it for the default).
  2. Watch letter casing — values are case-sensitive uppercase constants.
  3. Update compiler/tooling versions so validation rejects invalid @catch values with a proper diagnostic.
  4. Search your codebase for @catch usages and audit their to values.

Example fix

// before
field @catch(to: "null")
// after
field @catch(to: "NULL")
Defensive patterns

Strategy: validation

Validate before calling

const VALID_CATCH_TO = new Set(['NULL', 'RESULT']);
if (dir.name.value === 'catch') { const to = dir.arguments?.find(a => a.name.value === 'to'); if (to && !VALID_CATCH_TO.has(to.value.value)) throw new Error(`Invalid @catch to: ${to.value.value}`); }

Type guard

const isValidCatchTo = (v) => v === 'NULL' || v === 'RESULT';

Prevention

When it happens

Trigger: A @catch directive whose to argument parses to a StringKey that is neither RESULT nor NULL reaching the transform — i.e. a schema/validations gap allowed an unknown @catch(to:) value into the IR.

Common situations: Typo like @catch(to: "NULL_") or lowercase @catch(to: "null"); running a newer compiler against older validations or hand-crafted IR; upstream tools emitting non-standard @catch values.

Related errors


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