Bug
Lamdera apps with large FrontendModel records crash on Firefox with:
Uncaught internal error: too much recursion
The app works fine on Chrome and works locally (lamdera live) but fails in production (lamdera deploy).
Root Cause
In extra/Lamdera/Wire3/Decoder.hs (line 459), decodeRecord generates a decoder pipeline using foldlPairs (|>):
succeedDecode (\a b c ... -> { field1 = a, field2 = b, ... })
|> andMapDecode decoder1
|> andMapDecode decoder2
...
|> andMapDecode decoderN
Each |> compiles to a nested function call in JS. For apps with deeply nested records (e.g. a FrontendModel containing OwnerData containing forms, lists, etc.), the total chain can reach 380+ levels of nesting.
In the compiled production JS, this becomes:
i(X, i(Y, i(Z, ... i(W, u(fn)) ...)))
// 380+ nested calls
Firefox's call stack limit is ~5000 frames. With ~12-15 frames per decoder step, 380 steps × ~13 frames ≈ ~5000 frames → stack overflow on Firefox.
Chrome has a higher stack limit (~8800+) so it works there.
How to Reproduce
- Create a Lamdera app with a
FrontendModel that has many fields (including nested records with many fields)
- Deploy to production (
lamdera deploy)
- Open the deployed app in Firefox → "too much recursion" error
- Same app works in Chrome and locally with
lamdera live (non-optimized build)
Evidence
Analysis of the compiled production JS (frontend.*.js):
- Global max parenthesis nesting depth: 218 at the decoder chain
- 380 consecutive
i() calls (the compiled andMapDecode pipeline)
- The
i function is function(r,t){ return A4(function(n){ return L$(n,r) }, t) } — each call adds to the stack
Suggested Fix
In Decoder.hs, chunk the foldlPairs into groups to limit nesting depth:
Instead of:
foldlPairs (|>) -- creates a single chain of N steps
Split into batches of ~50 fields, decode each batch separately, then compose the results. This would cap the nesting depth regardless of record size.
Alternatively, the encoder (Encoder.hs line 237-254) already avoids this issue by using a flat list:
encodeSequenceWithoutLength $ list fieldEncoders
A similar flat approach for the decoder would eliminate the problem entirely.
Environment
- Firefox (any version — all have stricter stack limits than Chrome)
- Lamdera production builds (optimized + minified JS)
- App with ~100+ total fields across nested FrontendModel records
Bug
Lamdera apps with large
FrontendModelrecords crash on Firefox with:The app works fine on Chrome and works locally (
lamdera live) but fails in production (lamdera deploy).Root Cause
In
extra/Lamdera/Wire3/Decoder.hs(line 459),decodeRecordgenerates a decoder pipeline usingfoldlPairs (|>):Each
|>compiles to a nested function call in JS. For apps with deeply nested records (e.g. aFrontendModelcontainingOwnerDatacontaining forms, lists, etc.), the total chain can reach 380+ levels of nesting.In the compiled production JS, this becomes:
Firefox's call stack limit is ~5000 frames. With ~12-15 frames per decoder step, 380 steps × ~13 frames ≈ ~5000 frames → stack overflow on Firefox.
Chrome has a higher stack limit (~8800+) so it works there.
How to Reproduce
FrontendModelthat has many fields (including nested records with many fields)lamdera deploy)lamdera live(non-optimized build)Evidence
Analysis of the compiled production JS (
frontend.*.js):i()calls (the compiledandMapDecodepipeline)ifunction isfunction(r,t){ return A4(function(n){ return L$(n,r) }, t) }— each call adds to the stackSuggested Fix
In
Decoder.hs, chunk thefoldlPairsinto groups to limit nesting depth:Instead of:
Split into batches of ~50 fields, decode each batch separately, then compose the results. This would cap the nesting depth regardless of record size.
Alternatively, the encoder (
Encoder.hsline 237-254) already avoids this issue by using a flat list:encodeSequenceWithoutLength $ list fieldEncodersA similar flat approach for the decoder would eliminate the problem entirely.
Environment