hasura/graphql-engine · error · Error

failed to parse a number: {error:?}

Error message

failed to parse a number: {error:?}

What it means

Lexer error: the bytes looked like a number but lexical_core could not parse them as a valid numeric value (the underlying lexical error is in {error}). This catches numeric syntax that survives character scanning but violates numeric grammar, such as overflow of the target type or malformed float syntax.

Source

Thrown at v3/crates/graphql/lang-graphql/src/lexer/number.rs:28

    Float64(f64),
    // Int32(i32),
    Int64(i64),
}

impl Display for NumberToken {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            NumberToken::Float64(float) => float.fmt(f),
            NumberToken::Int64(i) => i.fmt(f),
        }
    }
}

#[derive(Error, Debug, PartialEq, Eq, Clone)]
pub enum Error {
    #[error("expected a digit, but found: {found:?}")]
    DigitExpected { found: Option<u8> },
    #[error("failed to parse a number: {error:?}")]
    LexicalError { error: lexical_core::Error },
    #[error("lookahead of a number cannot be a 'NameStart': {0:?}")]
    NameStart(u8),
}

pub fn parse_number(bytes: &[u8]) -> Result<(NumberToken, usize), Error> {
    let number_start = 0;
    let mut ix = 0;
    // Parse the optional negative sign
    if let Some(&b'-') = bytes.get(ix) {
        ix += 1;
    }
    // Count the number of integers present, until you hit a non-digit.
    // This helps to distinguish between integers and floats
    let integer_count = bytes[ix..]
        .iter()
        .take_while(|&&b| b.is_ascii_digit())
        .count();

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Pass the large value as a string variable and coerce server-side, or as a variable of the proper scalar type
  2. Fix the malformed exponent/float syntax
  3. Check the lexical error variant for overflow vs syntax

Example fix

# before
query { node(id: 9007199254740993) }
# after
query($id: bigint!) { node(id: $id) }
Defensive patterns

Strategy: validation

Validate before calling

// Bound inline integer literals to safe range or switch to variables
if (Math.abs(value) > Number.MAX_SAFE_INTEGER) useVariable();

Type guard

const isSafeInlineNumber = (n) => Number.isFinite(n) && Math.abs(n) <= Number.MAX_SAFE_INTEGER;

Try / catch

// On lexical number errors, inspect the variant: overflow -> variable; syntax -> fix literal

Prevention

When it happens

Trigger: Extremely large integer literals exceeding the representable range; malformed exponent notation like '1e+'; locale/format artifacts pasted into query text.

Common situations: Passing 64-bit IDs larger than the float/int literal limit as inline literals; copy-pasting numbers with exotic formatting.

Understand the failure class

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/fad6297eec04612e. Report an issue: GitHub.