phoenix_live_view icon indicating copy to clipboard operation
phoenix_live_view copied to clipboard

Form Change Event with missing params

Open maennchen opened this issue 3 years ago • 9 comments

I'm not exactly sure if this is the right place to report this problem since this might be either expected or a problem in the browser.

Environment

  • Elixir version (elixir -v): 1.11.3 (OTP 23.2.5)
  • Phoenix version (mix deps): 1.5.8
  • Phoenix LiveView version (mix deps): 0.15.4
  • NodeJS version (node -v): 14.16.0
  • NPM version (npm -v): 6.14.11
  • Operating system: Ubuntu 20.04.2 LTS
  • Browsers you attempted to reproduce this bug on (the more the merrier): Chrome / Firefox
  • Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: Yes

Actual behavior

I've forms that are set up as the phoenix generator does it (although using Surface):

<Form
  for={{ @changeset }}
  change="validate"
  submit="save"
  opts={{ autocomplete: "off", id: "person-form", "phx-hook": "BlockNavigation" }}
>
  <!-- ... -->
def handle_event("validate", %{"person" => person_params}, socket) do
  # ...

When trying this by hand it works as expected. With our Sentry tracing of the application, we catch a lot of FunctionClauseError:

FunctionClauseError: no function clause matching in HygeiaWeb.PersonLive.BaseData.handle_event/3
  File "lib/hygeia_web/live/person_live/base_data.ex", line 73, in HygeiaWeb.PersonLive.BaseData.handle_event/3
  File "lib/phoenix_live_view/channel.ex", line 338, in anonymous fn/3 in Phoenix.LiveView.Channel.view_handle_event/3
  File "/builds/hygeia/backend/deps/telemetry/src/telemetry.erl", line 262, in :telemetry.span/3
  File "lib/phoenix_live_view/channel.ex", line 203, in Phoenix.LiveView.Channel.handle_info/2
  File "gen_server.erl", line 689, in :gen_server.try_dispatch/4
  File "gen_server.erl", line 765, in :gen_server.handle_msg/6
  File "proc_lib.erl", line 226, in :proc_lib.init_p_do_apply/3

The supplied parameters look like this:

  • arg0 - "validate"
  • arg1 - %{"_csrf_token" => "cRcLJHkALCBDAlUBARMGemR2DFQhBzkE9eMvMAoNpEdJyzJCIDAcgOIB", "_method" => "put", "_target" => ["_method"]}
  • arg2 - socket

I myself can not reproduce the issue.

Unfortunately the application in which this error is caused is strictly confidential (health data / COVID19- Tracing) and therefore I do not have the possibility to get more information from the people causing the issue.

The error happens across all forms and are not localized to one resource.

Expected behavior

The event only to be triggered with the form parameters present in the event.

maennchen avatar Mar 22 '21 12:03 maennchen

The code producing the problem has since been released publicly:

https://github.com/jshmrtn/hygeia/blob/master/apps/hygeia_web/lib/hygeia_web/live/person_live/base_data.ex#L84

As said, this is only one occurrence of the error and it happens with all forms.

I'm still unable to reproduce it myself but see the errors reported on Sentry multiple times a day.

maennchen avatar Apr 22 '21 09:04 maennchen

A minimal example with a way to reliably reproduce the issue is going to be required to dig down into this one. On first glance, it looks like it could be related to the form recovery on disconnect, but that doesn't explain the missing form attributes. If you can provide a minimal repro please let us know. Thanks!

chrismccord avatar May 12 '21 15:05 chrismccord

@chrismccord I still don't have a way to reproduce the error.

It seems to be a general issue and not connected to any specific form.

The error occurred (across all different forms) 1'115 times in the last 90 days and it was caused by 35+ different users. (Not all users are authenticated, only counting the ones that were logged in.)

A few examples:

  • TransmissionLive
    • Sentry: https://sentry.joshmartin.ch/share/issue/0b262f4279eb4bba81893118b63bd111/
    • LiveView: https://github.com/jshmrtn/hygeia/blob/master/apps/hygeia_web/lib/hygeia_web/live/transmission_live/show.ex#L65
    • Template: https://github.com/jshmrtn/hygeia/blob/master/apps/hygeia_web/lib/hygeia_web/live/transmission_live/show.sface#L12
  • OrganisationLive
    • Sentry: https://sentry.joshmartin.ch/share/issue/6dbeebddc76041f58fe01e94979b358b/
    • LiveView: https://github.com/jshmrtn/hygeia/blob/master/apps/hygeia_web/lib/hygeia_web/live/organisation_live/show.ex#L71
    • Template: https://github.com/jshmrtn/hygeia/blob/master/apps/hygeia_web/lib/hygeia_web/live/organisation_live/show.sface#L78
  • DivisionLive
    • Sentry: https://sentry.joshmartin.ch/share/issue/a27c6f0a3ace4504ae62af691eb2966e/
    • LiveView: https://github.com/jshmrtn/hygeia/blob/master/apps/hygeia_web/lib/hygeia_web/live/division_live/show.ex#L67
    • Template: https://github.com/jshmrtn/hygeia/blob/master/apps/hygeia_web/lib/hygeia_web/live/division_live/show.sface#L47

If you have any ideas on how to reproduce the issue / debug the issue further, I'm willing to do an effort. I don't know where to start at the moment though.

maennchen avatar May 12 '21 17:05 maennchen

@maennchen one suggestion would be to add a catch-all clause and log what you are receiving, so we can see which parameters it is receiving, if any?

josevalim avatar May 12 '21 18:05 josevalim

Can you include a copy paste of the form HTML produced in the DOM when the page is rendered? You may also try recreating it by disabled live reload in development (remove from endpoint) and killing/restarting the server and watching the form recover.

chrismccord avatar May 12 '21 18:05 chrismccord

Oh, ignore me. I could not find the parameters on sentry but they are available in the initial report. If this is related to form recovery, as Chris suggested, then maybe you can try reproducing it by killing the server and starting it again to trigger form recovery.

josevalim avatar May 12 '21 18:05 josevalim

@chrismccord

Sure, this is the HTML:

divisions.html
<!DOCTYPE html>
<html lang="de-CH" data-sentry-enabled="true"
    data-sentry-dsn="https://[email protected]/2"
    data-sentry-user="{&quot;email&quot;:&quot;[email protected]&quot;,&quot;id&quot;:&quot;fe064d3a-9a86-4b5b-8a47-da98347f964f&quot;,&quot;name&quot;:&quot;Jonatan Männchen&quot;}">

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta charset="UTF-8" content="MGgzLD4hERxzOgs-Ek49A2JpIS5AAQEswYDyYXhEDbLvvwp20Pnwt8Qb" csrf-param="_csrf_token"
        method-param="_method" name="csrf-token">
    <title data-suffix=" - Hygeia">Aussendienst - Abteilung / Klasse - 11teamsports CH GmbH - Organisation - Hygeia
    </title>
    <link phx-track-static rel="stylesheet" href="/css/app-69bdeedb9231bffbea6538fb7fb6379f.css?vsn=d"
        integrity="sha512-FY2Qf8bWJx9NleBpQovnRJoRv4HdLstwyCVh3abb/9snDeJQFkYubSMxowPp8rwnMPa+SXKOKHX1VVA4Z4gWHQ=="
        nonce="Qs1fJc7grbvsE4QUpDepPsP65K37TNmBXKJcZmr-zEo" />
    <script type="text/javascript" nonce="cjL96pZBWCU1UZA1pL-Vo6AmqlRg_HK81fqFqGOD3mU">
        __webpack_nonce__ = "cjL96pZBWCU1UZA1pL-Vo6AmqlRg_HK81fqFqGOD3mU";
    </script>
    <script defer phx-track-static type="text/javascript" src="/js/app-8fb8989cef454dd06bb42082859132ec.js?vsn=d"
        integrity="" nonce="cjL96pZBWCU1UZA1pL-Vo6AmqlRg_HK81fqFqGOD3mU" crossorigin="anonymous"></script>

    <meta name="hygeia-translations"
        content="{&quot;Do you really want to continue without saving?&quot;:&quot;Möchten Sie fortfahren ohne die Änderungen zu speichern?&quot;}" />
</head>

<body class="layout-root">
    <div data-phx-main="true"
        data-phx-session="SFMyNTY.g2gDaAJhBHQAAAAHZAACaWRtAAAAFHBoeC1GbjVuNjNVNmFVTWRpaExCZAAKcGFyZW50X3BpZGQAA25pbGQACHJvb3RfcGlkZAADbmlsZAAJcm9vdF92aWV3ZAAiRWxpeGlyLkh5Z2VpYVdlYi5EaXZpc2lvbkxpdmUuU2hvd2QABnJvdXRlcmQAF0VsaXhpci5IeWdlaWFXZWIuUm91dGVyZAAHc2Vzc2lvbnQAAAAAZAAEdmlld2QAIkVsaXhpci5IeWdlaWFXZWIuRGl2aXNpb25MaXZlLlNob3duBgC1LAVieQFiAAFRgA.7o5muSm187zPexoFQhufsVOD7YYmQwfHOVxd2EGYGow"
        data-phx-static="SFMyNTY.g2gDaAJhBHQAAAADZAAKYXNzaWduX25ld2wAAAABZAALX19zdXJmYWNlX19qZAAFZmxhc2h0AAAAAGQAAmlkbQAAABRwaHgtRm41bjYzVTZhVU1kaWhMQm4GALUsBWJ5AWIAAVGA.K1FhuYk0mG0rd9VeT-u5uok9tdvtUL1jE_OBNoBvO_w"
        data-phx-view="DivisionLive.Show" id="phx-Fn5n63U6aUMdihLB">
        <div class="system-messages" phx-hook="HideAlert">

        </div>

        <header class="layout-header py-3 bg-dark mb-5">

            <section class="container">
                <div class="d-flex justify-content-between">
                    <ul class="nav nav-pills" role="navigation">
                        <div class="navbar-brand">
                            <a data-phx-link="redirect" data-phx-link-state="push" href="/">
                                <img class="nav-item logo img-fluid"
                                    src="/images/hygeia-logo-ef02387e41f93bfef2f0420786f5f47f.svg?vsn=d">
                            </a>

                        </div>
                        <li class="nav-item">


                            <a class="nav-link" data-phx-link="redirect" data-phx-link-state="push" href="/cases">
                                Fälle
                            </a>





                        </li>
                        <li class="nav-item">


                            <a class="nav-link" data-phx-link="redirect" data-phx-link-state="push" href="/people">
                                Personen
                            </a>





                        </li>
                        <li class="nav-item">


                            <a class="nav-link" data-phx-link="redirect" data-phx-link-state="push" href="/statistics">
                                Statistiken
                            </a>





                        </li>
                        <li class="nav-item dropdown" phx-update="ignore" id="nav-ignore">
                            <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button"
                                aria-haspopup="true" aria-expanded="false">
                                Mehr
                            </a>
                            <div class="dropdown-menu">
                                <a class="dropdown-item" href="/dashboard">
                                    Phoenix Dashboard
                                </a>

                                <a class="dropdown-item" href="/users">
                                    Benutzer
                                </a>

                                <a class="dropdown-item" href="/tenants">
                                    Mandanten
                                </a>

                                <a class="dropdown-item" href="/organisations">
                                    Organisationen
                                </a>

                                <a class="dropdown-item" href="/system_messages">
                                    Systemnachrichten
                                </a>

                            </div>
                        </li>
                    </ul>
                    <div class="nav nav-pills">
                        <li class="nav-item mr-3">
                            <div data-phx-parent-id="phx-Fn5n63U6aUMdihLB" data-phx-session=""
                                data-phx-static="SFMyNTY.g2gDaAJhBHQAAAADZAAKYXNzaWduX25ld2wAAAABZAALX19zdXJmYWNlX19qZAAFZmxhc2h0AAAAAGQAAmlkbQAAAAZzZWFyY2huBgC4LAVieQFiAAFRgA.h2oppOWpgt3HKVGk0hTNz3-JwFCby1w2eTZr9GOmlAo"
                                data-phx-view="Search" id="search">
                                <form phx-change="search" class="component-search">

                                    <div class="input-group">
                                        <div class="input-group-prepend">
                                            <span class="input-group-text border-0">
                                                <span class="oi oi-magnifying-glass" aria-hidden="true"></span>
                                            </span>
                                        </div>


                                        <input autocomplete="off" class="form-control border-0" id="_" name="query"
                                            phx-focus="open" placeholder="Suche" type="search">





                                    </div>




                                </form>
                            </div>
                        </li>
                        <li class="nav-item">


                            <a class="nav-link" data-phx-link="redirect" data-phx-link-state="push" href="/help">
                                <span class="oi oi-question-mark" title="Hilfe" aria-hidden="true"></span>
                            </a>





                        </li>
                        <li class="nav-item text-primary">
                            <div data-phx-parent-id="phx-Fn5n63U6aUMdihLB" data-phx-session=""
                                data-phx-static="SFMyNTY.g2gDaAJhBHQAAAADZAAKYXNzaWduX25ld2wAAAABZAALX19zdXJmYWNlX19qZAAFZmxhc2h0AAAAAGQAAmlkbQAAABloZWFkZXJfbm90aWZpY2F0aW9uc190cmF5bgYAuSwFYnkBYgABUYA.e85R1eRsFss6NTnROuyEZzfcLd-zcnLNGAJTGELDyDo"
                                data-phx-view="Notification.Tray" id="header_notifications_tray">
                                <div tabindex="-1" id="notifications-try-dropdown_dropdown" phx-target="1"
                                    phx-hook="Dropdown" class="dropdown open dropleft">
                                    <div phx-click="toggle_dropdown" phx-target="1" class="nav-link">

                                        <button class="nav-item notification-tray-trigger">
                                            <span class="oi oi-bell" title="Benachrichtigungen"></span>

                                        </button>

                                    </div>

                                    <div class="dropdown-menu notification-tray-content">

                                        <div class="dropdown-item actions">
                                            <button phx-click="read_all" class="btn btn-secondary btn-sm">
                                                <span class="oi oi-check" aria-hidden="true"></span>
                                                Alle als gelesen markieren
                                            </button>
                                            <button phx-click="delete_all" class="btn btn-danger btn-sm"
                                                data-confirm="Are you sure?">
                                                <span class="oi oi-trash" aria-hidden="true"></span>
                                                Alle löschen
                                            </button>
                                        </div>
                                        <div class="scroll-container">

                                        </div>

                                    </div>
                                </div>

                            </div>
                        </li>
                        <li class="nav-item">
                            <div class="dropdown" id="profile" phx-update="ignore">
                                <a class="nav-link" type="button" data-toggle="dropdown" aria-haspopup="true"
                                    aria-expanded="false">
                                    <span class="oi oi-person" title="Profil" aria-hidden="true"></span>
                                </a>
                                <div class="nav-dropdown dropdown-menu dropdown-menu-right">
                                    <div class="dropdown-item">
                                        Jonatan Männchen
                                    </div>



                                    <a class="dropdown-item" data-phx-link="redirect" data-phx-link-state="push"
                                        href="/users/fe064d3a-9a86-4b5b-8a47-da98347f964f">
                                        Profil
                                    </a>






                                    <a class="dropdown-item" href="/auth">
                                        Abmelden
                                    </a>

                                </div>
                            </div>
                        </li>

                    </div>
                </div>
            </section>


        </header>

        <main role="main" class="layout-live-main">
            <div class="container">
                <p class="alert alert-info" role="alert" phx-click="lv:clear-flash" phx-value-key="info"></p>

                <p class="alert alert-danger" role="alert" phx-click="lv:clear-flash" phx-value-key="error"></p>
            </div>
            <div class="component-organisation-base-data container">

                <div class="component-person-header mb-4">

                    <h1 class="mb-4">
                        <span>
                            <a data-phx-link="redirect" data-phx-link-state="push"
                                href="/organisations/24d8ecfb-7da8-40d6-bd8e-a2508b0d91f5">
                                11teamsports CH GmbH
                            </a>

                            /
                        </span>
                        <span>
                            Aussendienst
                        </span>

                    </h1>

                    <ul class="nav nav-tabs">
                        <li class="nav-item">


                            <a class="nav-link" data-phx-link="redirect" data-phx-link-state="push"
                                href="/divisions/08c24e28-8647-44fb-ba2d-360fb22e5fd9">
                                Basisdaten
                            </a>





                        </li>
                        <li class="nav-item">


                            <a class="nav-link" data-phx-link="redirect" data-phx-link-state="push"
                                href="/history/divisions/08c24e28-8647-44fb-ba2d-360fb22e5fd9">
                                Änderungsverlauf
                            </a>





                        </li>

                        <div tabindex="-1" id="navigation-dropdown_dropdown" phx-target="4" phx-hook="Dropdown"
                            class="dropdown ml-auto">
                            <div phx-click="toggle_dropdown" phx-target="4"
                                class="btn btn-sm btn-secondary dropdown-toggle">

                                Aktionen

                            </div>

                            <div class="dropdown-menu dropdown-menu-right">





                                <a class="dropdown-item nav-link" data-phx-link="redirect" data-phx-link-state="push"
                                    href="/organisations/24d8ecfb-7da8-40d6-bd8e-a2508b0d91f5/divisions/merge?delete=08c24e28-8647-44fb-ba2d-360fb22e5fd9">
                                    Fusionieren
                                </a>






                            </div>
                        </div>

                    </ul>


                </div>




                <form action="#" autocomplete="off" id="division-form" method="post" phx-change="validate"
                    phx-hook="BlockNavigation" phx-submit="save"><input name="_method" type="hidden" value="put"><input
                        name="_csrf_token" type="hidden"
                        value="MGgzLD4hERxzOgs-Ek49A2JpIS5AAQEswYDyYXhEDbLvvwp20Pnwt8Qb">


                    <div>

                        <div>
                            <div class="mb-4">
                                <button class="btn btn-primary mr-2" type="submit" phx-disable-with="Speichern...">
                                    <span class="oi oi-circle-check" title="Speichern" aria-hidden="true"></span>
                                    Speichern
                                </button>
                                <button phx-click="reset" class="btn btn-warning" type="button">
                                    <span class="oi oi-circle-x" title="Verwerfen" aria-hidden="true"></span>
                                    Verwerfen
                                </button>
                            </div>
                        </div>

                        <div class="hy-card-grid-2-cols hy-readonly-form">
                            <div class="card">
                                <div class="card-body">
                                    <h4 class="card-title">Name</h4>

                                    <div class="form-group">






                                        <label for="division-form_title">


                                            Titel


                                        </label>












                                        <input class="form-control" id="division-form_title" name="division[title]"
                                            type="text" value="Aussendienst">
















                                    </div>


                                    <div class="form-group">






                                        <label for="division-form_description">


                                            Beschreibung


                                        </label>












                                        <textarea class="form-control" id="division-form_description"
                                            name="division[description]">
</textarea>
















                                    </div>

                                </div>
                            </div>

                            <div class="card">
                                <div class="card-body">
                                    <h4 class="card-title">Adresse</h4>

                                    <div class="form-group">






                                        <label for="division-form_shares_address">


                                            Teilt Hauptadresse


                                        </label>












                                        <input name="division[shares_address]" type="hidden" value="false"><input
                                            class="form-control" id="division-form_shares_address"
                                            name="division[shares_address]" type="checkbox" value="true" checked>
















                                    </div>












                                </div>
                            </div>
                        </div>


                    </div>




                </form>



            </div>

        </main>
    </div>
</body>

</html>

I'll try to reproduce it as you said. I'll post the results. (It Will probably take until Monday to test it.)

maennchen avatar May 12 '21 19:05 maennchen

This is almost positively form recovery, though I usually see it with "_target" => ["_csrf_token"]. Since we don't have a change event to crib from, form recovery always target the first control in the form, which by default will be a hidden field.

Edit: To clarify, a hidden input will be the first form control by default when using Phoenix.HTML.form_for/4 and variants.

mcrumm avatar May 12 '21 23:05 mcrumm

@mcrumm / @chrismccord

I tried the following without any effect:

Disconnect Network

  • Open a Form
  • Disconnect from WiFi and wait for a few minutes
  • Reconnect
  • => no error

kill application

  • Open a Form
  • Kill Application
  • Restart Application
  • => no error

kill K8S Pod

  • Open a Form in a Test Environment
  • Kill Kubernetes Pod that opened the connection
  • Reconnects to other pod
  • => no error

maennchen avatar May 18 '21 07:05 maennchen

Can this issue be related to form recovery process? Read README and see example in this repo.

I have also provided a solution for form recovery process https://github.com/phoenixframework/phoenix_live_view/pull/2181.

cr0t avatar Nov 20 '22 12:11 cr0t

Forms need an ID to support recovery. Can you add an ID to your form example and report back? Thanks!

chrismccord avatar Nov 28 '22 20:11 chrismccord

@maennchen It seems that there was no way to reproduce reliably in the end? Or did the last two suggestions above help? Otherwise, we should probably close this issue.

Rio517 avatar Feb 22 '23 10:02 Rio517

@Rio517 I still do not have a way to reproduce the issue. That said, I can still see the same errors in our Sentry.

maennchen avatar Feb 22 '23 10:02 maennchen