facebook/flow · error · Error

Type size limit exceeded

Error message

Type size limit exceeded

What it means

This error is thrown by the type normalizer when the normalization of a type visits more type nodes than the configured budget (max_type_size) allows. State::consume_type_node decrements a counter for every type node visited; when the counter is already 0, it fails with ErrorKind::TypeSizeLimit and message "Type size limit exceeded". The limit exists to guard against pathologically large or recursive types blowing up normalization time/memory.

Solutions

  1. Increase the configured maximum type size passed to reset_type_size_budget (raise the budget for the analysis run).
  2. Check the type being normalized for accidental blowup (recursive alias expansion, excessively large unions/tuples) and simplify it in the source program.
  3. If the limit is intentional, treat this error as a signal to bail out of normalizing that type and fall back to a normalized-type approximation or report a user-facing type-too-complex diagnostic.
  4. Verify the budget is not being reset/decremented across unrelated types, which would unfairly deplete it for later types.

Example fix

// before
state.reset_type_size_budget(Some(1024));
// after
state.reset_type_size_budget(Some(4096));
Defensive patterns

Strategy: try-catch

Validate before calling

// estimate node count before normalizing and skip if over budget
fn within_budget(ty: &Ty, budget: usize) -> bool {
    ty.node_count() <= budget
}

Type guard

fn is_type_size_limit(e: &Error) -> bool {
    e.kind() == ErrorKind::TypeSizeLimit
}

Try / catch

match state.normalize(ty) {
    Ok(n) => n,
    Err(e) if e.kind() == ErrorKind::TypeSizeLimit => {
        // fall back: use un-normalized type or emit "type too complex" diagnostic
        fallback_representation(ty)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Normalizing a type whose AST has more nodes than the remaining budget: a State with remaining_type_size = Some(n) where consuming more than n nodes is required. This happens when reset_type_size_budget was called with a small max, or the type being normalized is genuinely huge/deeply recursive.

Common situations: Very large generated or deeply nested types (e.g. huge trait objects, long tuple/union chains), mutually recursive type aliases expanded during normalization, or a max type size configured too low for the codebase being type-checked.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of facebook/flow@21c11b2ead (2026-09-16). Data as JSON: /api/errors/3e2c5ed29d7105bd. Report an issue: GitHub.

Appendix: source

Thrown at rust_port/crates/flow_typing_ty_normalizer/src/normalizer.rs:355

            rec_tvar_ids: BTreeSet::new(),
            rec_eval_ids: BTreeSet::new(),
            found_computed_type: false,
            remaining_type_size: None,
        }
    }

    pub fn found_computed_type(&self) -> bool {
        self.found_computed_type
    }

    fn reset_type_size_budget(&mut self, max_type_size: Option<usize>) {
        self.remaining_type_size = max_type_size;
    }

    fn consume_type_node(&mut self) -> Result<(), Error> {
        match self.remaining_type_size {
            None => Ok(()),
            Some(0) => Err(Error::new(
                ErrorKind::TypeSizeLimit,
                String::from("Type size limit exceeded"),
            )),
            Some(remaining) => {
                self.remaining_type_size = Some(remaining - 1);
                Ok(())
            }
        }
    }
}

// Each run of the monad gets assigned its own id.
thread_local! {
    static RUN_ID: Cell<i32> = const { Cell::new(0) };
}

// Wrapper around 'run' that assigns a distinct id to every run of the monad.
fn run<T, F>(state: &mut State, f: F) -> Result<T, Error>

View on GitHub (pinned to 21c11b2ead)