Skip to content

Fix decode/1 crash on non-JSON strings from search input#133

Open
mcass19 wants to merge 2 commits intomaxmarcon:mainfrom
mcass19:fix-decode-crash
Open

Fix decode/1 crash on non-JSON strings from search input#133
mcass19 wants to merge 2 commits intomaxmarcon:mainfrom
mcass19:fix-decode-crash

Conversation

@mcass19
Copy link
Copy Markdown
Contributor

@mcass19 mcass19 commented Feb 16, 2026

Hi, it's me again :). Keep the nice work and library!!!

Problem

LiveSelect.decode/1 crashes with a Jason.DecodeError when the value passed to it is a plain string that isn't valid JSON.

This happens when a form with phx-change fires while the user is typing in the LiveSelect text input but hasn't made a selection yet. The raw search text (e.g., "Glon") arrives as the field value, and decode/1 crashes because unquoted text is not valid JSON.

** (Jason.DecodeError) unexpected byte at position 0: 0x47 ("G")
    (jason 1.4.4) lib/jason.ex:92: Jason.decode!/2
    (elixir 1.19.0) lib/kernel.ex:2983: anonymous fn/2 in Kernel.update_in/3
    (elixir 1.19.0) lib/map.ex:965: Map.get_and_update/3
    (elixir 1.19.0) lib/kernel.ex:2983: Kernel.update_in/3

How to reproduce

  1. Create a form with phx-change="validate" containing a LiveSelect field (e.g., user_id)
  2. In the handle_event("validate", ...), call LiveSelect.decode/1 on the field value as shown in the docs:
    params = update_in(params, ~w(my_form my_field), &LiveSelect.decode/1)
  3. Type text into the LiveSelect search input (e.g., "Glon") without selecting an option
  4. Trigger a form change event (e.g., by changing another field, or by the _target hitting the LiveSelect field)

The raw search text arrives as the field value, and decode/1 crashes.

Root cause

There is an asymmetry between encode and decode.
In component.ex, encode/1 has a fast path that skips JSON encoding for simple types. But decode/1 in live_select.ex always calls json.decode! on any non-nil, non-empty value.

This means values that were never JSON-encoded (simple strings, raw text from typing) get json.decode! called on them, which crashes.

Fix

Rescue decode errors and return the raw value as-is, mirroring how encode/1 passes simple types through without encoding.

This way, valid JSON is decoded as before, and non-JSON strings pass through to the changeset which handles validation normally.

There's a test added that fails without the fix.

Covers the case where raw search text (e.g. "Glon") is passed
to decode/1 before a selection is made. Currently crashes with
Jason.DecodeError.
Rescue decode errors and return the raw value as-is, mirroring
how encode/1 already passes simple types through without encoding.
@maxmarcon
Copy link
Copy Markdown
Owner

Thanks for this. I will look into this as soon as I have some time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants