Debugging JSON Decoder Failures in Elm 0.19
A diagnostic guide for resolving JSON decoder failures in Elm 0.19, covering shape mismatches, nullable fields, and REPL-based verification techniques.
01 Aug 2026, 10:06 UTC

The Problem: Silent UI Failures and Decoder Mismatches
In Elm 0.19, a successful compilation does not guarantee that your application will handle external data correctly. Because JSON decoders operate at runtime, a mismatch between your elm/json decoder and the actual API payload will result in a failed Http.expectJson call. This typically manifests as a UI that remains in a loading state, renders empty lists, or reverts to default values without any compiler warnings.
Diagnostic Matrix: Identifying the Root Cause
When the UI fails to populate after a data fetch, use this table to categorize the failure based on the observed behavior.
| Symptom | Likely Cause | Diagnostic Signal |
|---|---|---|
| UI stays in 'Loading' or 'Empty' state | Decoder shape mismatch | Http.BadStatus or Http.BadBody in the Update msg |
| App fails to boot (blank screen) | Flags decoder mismatch | Browser console error during Browser.element init |
| Wrong data in specific fields | Overly permissive oneOf |
Decoder succeeds but maps to the wrong variant |
| Intermittent failures on some records | Nullable API keys | Decode.field fails when a key is missing or null |
Ordered Verification Steps
Follow these steps to isolate whether the issue lies in the network payload, the decoder logic, or the application state update.
- Capture the Raw Payload: Open the Browser Developer Tools (Network tab), trigger the request, and copy the raw JSON response body.
- Isolate in REPL: Run
elm replin your terminal. Paste the raw JSON string and attempt to decode it manually using your decoder. This removes the browser and HTTP layer from the equation.-- Example REPL check Decode.decodeString.result myDecoder "{\"id\": 1, \"name\": \"Test\"}" - Verify the Init Path: If the failure happens at startup, compare the
flagsdecoder in yourinitfunction against the actual flags passed toelm.initin your JavaScript index file. - Trace the Update Loop: Ensure that the
Http.expectJsonresult is actually being handled in yourupdatefunction and that the resulting model is being returned, not discarded.
Fixes Based on Findings
Depending on the REPL results, apply the corresponding fix to your decoder definition.
Finding: Field Name or Type Mismatch
If the REPL returns Failure "Expected ... but got ...", align the decoder with the API. Ensure Decode.int is used for integers and Decode.float for decimals.
Finding: Missing or Null Keys
If the API occasionally omits keys or returns null, Decode.field will fail the entire record. Replace it with Decode.optionalField to provide a default value.
-- Before: Fails if "bio" is missing
Decode.field "bio" Decode.string
-- After: Defaults to empty string if "bio" is missing or null
Decode.optionalField "bio" Decode.string
Finding: Polymorphic Responses
If the API returns different shapes for the same endpoint (e.g., an error object vs. a data object), use Decode.oneOf. Be cautious: order matters, as the first decoder that succeeds will be used.
Finding: Opaque Failures in Production
To make errors visible during development without relying on Debug.log (which is stripped in production), wrap your decoder in Decode.mapError to add context to the failure string.
Verification and Limitations
To verify the fix, restart the development server and trigger the API call. Confirm that the Http.expectJson handler receives the Ok variant.
Limitations: Note that elm/json decoders are strict. If an API changes a field from an Integer to a Float, the decoder will fail even if the numerical value is the same. Always verify the exact JSON type in the network tab.
Rollback Procedure
If a decoder change causes regressions in other parts of the app, revert the Decode function to its previous state. Since decoders are pure functions, this change does not affect the database or persistent state, only how the application interprets incoming data.
Escalation Criteria
- Backend Contract Breach: If the raw payload deviates from the agreed-upon API documentation despite your decoder being correct, escalate to the backend team.
- Architecture Mismatch: If you find yourself writing deeply nested
oneOfblocks to handle inconsistent data, consider implementing a data transformation layer in JavaScript before passing the data into Elm as flags.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.