Hidden Assumptions in remix

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

Every codebase relies on things it never checks. Most of them are routine. CodeSea looked at remix-run/remix 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 stored context has wrong shape (missing required properties, wrong types), the cast succeeds but downstream code crashes with property access errors like 'Cannot read property of undefined'

Worth your attention first

In non-Node environments (browsers, Deno, Bun) or Node versions < 14.17, the import throws 'module not found' or AsyncLocalStorage is undefined, breaking the entire middleware

Worth your attention first

When comparing expiresAt with current time across different server timezones or daylight saving transitions, tokens may be considered expired when valid or valid when expired

Show everything (10 more)
Ordering

asyncContext middleware executes before any middleware that calls getContext(), but no ordering constraints are enforced

If this fails: If getContext() is called before asyncContext runs, it throws 'No request context found' error, but this dependency is only discoverable at runtime

packages/async-context-middleware/src/lib/async-context.ts:asyncContext
Contract

All AuthScheme implementations return AuthSchemeResult with consistent identity types, but no runtime type checking exists between schemes

If this fails: If one scheme returns identity as string while another returns object, handlers accessing context.get(Auth).identity crash with type errors when switching auth methods

packages/auth-middleware/src/lib/auth.ts:AuthScheme.authenticate
Scale

1024 byte default compression threshold works for all response types, but small JSON responses under this limit bypass compression even when highly compressible

If this fails: API endpoints returning repetitive JSON data (like arrays of similar objects) miss significant compression opportunities, increasing bandwidth usage and response times

packages/compression-middleware/src/lib/compression.ts:threshold
Contract

Content-Type header always contains valid MIME type format 'type/subtype', but malformed headers are not validated

If this fails: If Content-Type header contains malformed values like 'invalid' or 'text', mediaType.split(';')[0] produces unexpected results and compression may apply to inappropriate responses

packages/compression-middleware/src/lib/compression.ts:filterMediaType
Resource

compressResponse can handle any response body size in memory, but no size limits or streaming checks exist

If this fails: Attempting to compress very large response bodies (like file downloads) causes out-of-memory errors or blocks the event loop during compression

packages/compression-middleware/src/lib/compression.ts:compressResponse
Temporal

Cookie secrets array represents rotation order with newest first, but no validation ensures secrets don't repeat or become empty

If this fails: If secrets array becomes empty or contains duplicates, cookie signing fails silently or produces predictable signatures, breaking authentication security

packages/cookie/src/lib/cookie.ts:secrets
Domain

Cookie expires Date uses browser's local timezone interpretation, but server-side Date creation uses server timezone

If this fails: When server and client are in different timezones, cookies expire at unexpected times - either too early (user gets logged out) or too late (security risk)

packages/cookie/src/lib/cookie.ts:expires
Ordering

Cross-origin protection checks execute after CORS middleware has set appropriate headers, but middleware ordering is not enforced

If this fails: If COP runs before CORS, legitimate preflight OPTIONS requests get blocked as cross-origin attacks, breaking CORS-enabled APIs

packages/cop-middleware/src/lib/cop.ts:check
Contract

Trusted origins are exact string matches including protocol and port, but origin normalization rules are not documented

If this fails: Origins like 'https://example.com:443' don't match 'https://example.com' even though browsers normalize them as identical, causing legitimate requests to be blocked

packages/cop-middleware/src/lib/cop.ts:trustedOrigins
Shape

Signal<string> objects maintain referential stability during data transformations, but array operations create new signal instances

If this fails: When sortAsc() rebuilds signal rows, existing component subscriptions to old signal instances become orphaned, causing UI to stop updating until full re-render

packages/component/bench/frameworks/preact-signals/index.tsx:Row

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

Full analysis of remix-run/remix →

Frequently Asked Questions

What does remix assume that could break in production?

The one most likely to cause trouble: AsyncLocalStorage.getStore() returns the exact same RequestContext type that was stored, but the function casts it blindly with 'as AsyncRequestContext' without runtime validation If this fails, If the stored context has wrong shape (missing required properties, wrong types), the cast succeeds but downstream code crashes with property access errors like 'Cannot read property of undefined'

How many hidden assumptions does remix have?

CodeSea found 13 assumptions remix relies on but never validates, 5 of them critical, spanning Shape, Environment, Ordering, Domain, Contract, Scale, Resource, Temporal. 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.