Hidden Assumptions in rollup

13 assumptions this code never checks · 4 critical · spanning Shape, Ordering, Contract, Temporal, Resource, Domain, Scale, Environment

Every codebase relies on things it never checks. Most of them are routine. CodeSea looked at rollup/rollup and picked out the few most likely to cause trouble. The full list is just below.

Most of what this code assumes is routine. These 3 are the ones most likely to cause trouble here. The rest are minor; they're under "Show everything".

Worth your attention first

If the Rust parser changes its serialization format or the TypeScript deserializer misreads the buffer, nodes will be created with wrong types, corrupted positions, or malformed structures, causing silent AST corruption throughout the bundling process

Worth your attention first

If scope resolution fails (circular imports, temporal dead zones, complex destructuring), this.variable remains null but the code continues processing, leading to null pointer exceptions when the identifier is later used for tree-shaking or rendering

Worth your attention first

If plugins return inconsistent module IDs for the same import or return malformed objects instead of strings, the module cache becomes corrupted and the same module may be loaded multiple times with different IDs, breaking dependency analysis

Show everything (10 more)
Temporal

The EntityPathTracker and DiscriminatedPathTracker instances created in HasEffectsContext remain valid for the entire tree-shaking analysis phase and aren't modified concurrently by other parts of the system

If this fails: If these trackers are mutated during analysis by parallel processing or plugin interference, the tree-shaking algorithm will make incorrect inclusion decisions, potentially including dead code or excluding live code

src/ast/ExecutionContext.ts:createHasEffectsContext
Resource

The Node.js event loop can handle the Rust async parsing tasks without blocking, and that system memory is sufficient to hold both the original source code string and the serialized AST buffer simultaneously

If this fails: For very large files, the system may run out of memory when both the input string and output buffer exist at the same time, or the event loop may be starved if too many parse tasks are queued, causing the bundler to hang or crash

rust/bindings_napi/src/lib.rs:parse_async
Domain

JavaScript well-known symbols (Symbol.toStringTag, Symbol.hasInstance, etc.) have stable identities across all environments and that future ECMAScript versions won't introduce conflicting symbol semantics

If this fails: If symbol behavior changes in newer JavaScript engines or if polyfills create different symbol instances, the symbol-based property tracking will fail to correctly identify well-known symbol accesses, breaking tree-shaking for code using these symbols

src/ast/utils/PathTracker.ts:WELL_KNOWN_SYMBOLS
Scale

The nested Map structure in EntityPathTracker can efficiently handle deeply nested object path tracking without hitting JavaScript's recursion limits or memory constraints, even for complex codebases with deep property access chains

If this fails: For extremely deep object property accesses (obj.a.b.c...z), the tracker's nested Map structure may consume excessive memory or hit stack overflow during traversal, causing tree-shaking to fail or produce incorrect results

src/ast/utils/PathTracker.ts:EntityPathTracker
Environment

The WebAssembly runtime environment supports the Rust-compiled parser with sufficient stack space and linear memory, and that WASM's memory model is compatible with the AST buffer serialization format

If this fails: If the WASM runtime has insufficient memory or stack space, or if the memory layout differs from native execution, the parser will crash or produce corrupted AST data, breaking the entire bundling process in browser environments

rust/bindings_wasm/src/lib.rs:parse
Contract

The scope.addDeclaration method correctly handles all variable kinds (var, let, const, parameter) and that treeshake options remain consistent throughout the declaration phase - specifically that treeshake.correctVarValueBeforeDeclaration doesn't change mid-build

If this fails: If treeshake options change during bundling or if scope.addDeclaration fails to properly handle certain variable kinds, variable hoisting and initialization timing will be incorrect, leading to wrong tree-shaking decisions and potentially broken output code

src/ast/nodes/Identifier.ts:declare
Ordering

The includedCallArguments Set maintains insertion order for function call argument processing and that arguments are processed in the same order they appear in the source code

If this fails: If argument processing order is inconsistent, side effects from function calls may be analyzed in the wrong sequence, potentially marking pure functions as having effects or missing side effects from impure arguments

src/ast/ExecutionContext.ts:InclusionContext
Temporal

The mem::take(&mut self.code) operation assumes that the code string won't be needed again after parsing and that the ParseTask instance lifecycle aligns with the async task completion

If this fails: If the parsing task needs to retry or if the code is accessed after mem::take, the operation will panic or produce empty results, but this is more of a design constraint than a hidden failure mode

rust/bindings_napi/src/lib.rs:ParseTask
Domain

The symbolic representation of unknown object keys (UnknownKey, UnknownInteger, etc.) covers all possible dynamic property access patterns in JavaScript code and that no new access patterns will emerge

If this fails: If new JavaScript features introduce property access patterns not covered by the existing unknown key symbols, those accesses won't be properly tracked during tree-shaking, potentially causing over-aggressive elimination of code that has dynamic dependencies

src/ast/utils/PathTracker.ts:UnknownKey
Resource

The mimalloc allocator is available and compatible with the target platform, and that it provides better performance than the system allocator for the AST parsing workload

If this fails: If mimalloc fails to initialize or has compatibility issues on certain platforms, the Rust parser will fall back to system allocation, which may cause performance degradation but shouldn't break functionality

rust/bindings_napi/src/lib.rs:ALLOC

See the full structural analysis of rollup: the pipeline, data models, and system behavior that put these assumptions in context.

Full analysis of rollup/rollup →

Frequently Asked Questions

What does rollup assume that could break in production?

The one most likely to cause trouble: The Rust parser produces SerializedAstBuffer with a specific binary format that matches the TypeScript deserializer's expectations exactly - node type IDs, byte offsets, nested structure encoding, and string table layout must all align perfectly If this fails, If the Rust parser changes its serialization format or the TypeScript deserializer misreads the buffer, nodes will be created with wrong types, corrupted positions, or malformed structures, causing silent AST corruption throughout the bundling process

How many hidden assumptions does rollup have?

CodeSea found 13 assumptions rollup relies on but never validates, 4 of them critical, spanning Shape, Ordering, Contract, Temporal, Resource, Domain, Scale, Environment. Most are routine — the analysis flags the two or three most likely to actually bite.

What is a hidden assumption?

Something the code depends on but never checks: a data shape, an ordering, an environment condition, a scale limit, or a contract with another service. It holds until the world it runs in changes, then fails silently.