-
Notifications
You must be signed in to change notification settings - Fork 437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Livebook Freezes and Crashes #2158
Comments
Does it work if you add explicit |
Okay if I pin the value then nothing crashes: from(sub in Db.SubMenu,
where: sub.id == ^"01FXJX305X2MPZK5XFMVEK780F"
)
|> Repo.all() So it feels like:
No kino packages installed. |
Does it happen for you with this notebook? ecto.livemd# Ecto
```elixir
Mix.install([
{:ecto, "~> 3.6"},
{:ecto_sql, "~> 3.6"},
{:postgrex, "~> 0.15"}
])
```
## Setup
```
docker run --rm -it -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -p 5566:5432 postgres:13.2
```
## Query
```elixir
defmodule Repo do
use Ecto.Repo, otp_app: :my_app, adapter: Ecto.Adapters.Postgres
end
```
```elixir
Repo.start_link(url: "postgres://postgres:postgres@localhost:5566/postgres")
```
```elixir
Ecto.Adapters.SQL.query!(Repo, "create table users (id uuid)")
```
```elixir
import Ecto.Query, only: [from: 2]
query =
from(u in "users",
where: u.id == "TMGz8OmBStKlnqgo",
select: u.id
)
Repo.all(query)
``` You can also try the exact ecto/postgrex versions your using. |
@Adzz ping! |
Apologies, thanks for the ping! The output if I run that is: ** (Postgrex.Error) ERROR 22P02 (invalid_text_representation) invalid input syntax for type uuid: "TMGz8OmBStKlnqgo". If you are trying to query a JSON field, the parameter may need to be interpolated. Instead of
p.json["field"] != "value"
do
p.json["field"] != ^"value"
query: SELECT u0."id" FROM "users" AS u0 WHERE (u0."id" = 'TMGz8OmBStKlnqgo')
(ecto_sql 3.10.2) lib/ecto/adapters/sql.ex:1047: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto_sql 3.10.2) lib/ecto/adapters/sql.ex:945: Ecto.Adapters.SQL.execute/6
(ecto 3.10.3) lib/ecto/repo/queryable.ex:229: Ecto.Repo.Queryable.execute/4
(ecto 3.10.3) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
#cell:ekuvvpbi66cmrpqtjzrw5qun5jeingua:9: (file) But livebook doesn't crash or hang If I use a pin in your example it works: import Ecto.Query, only: [from: 2]
query =
from(u in "users",
where: u.id == ^"TMGz8OmBStKlnqgo",
select: u.id
)
Repo.all(query) returns |
I see, so it seems the reason it crashes is specific to your query. In that case it would be helpful if you could run Livebook main in dev mode and inspect the message here (for the original error): livebook/lib/livebook_web/live/output.ex Line 357 in 7bcdd90
|
Ping :) |
I cloned main and ran the original livebook using it. I see a few things. The error that loops continuously is: 12:40:58.105 [error] Ranch listener LivebookWeb.Endpoint.HTTP had connection process started with :cowboy_clear:start_link/4 at #PID<0.1408.0> exit with reason: {%Jason.EncodeError{message: "invalid byte 0xBD in <<60, 115, 112, 97, 110, 32, 115, 116, 121, 108, 101, 61, 34, 99, 111, 108, 111, 114, 58, 32, 118, 97, 114, 40, 45, 45, 97, 110, 115, 105, 45, 99, 111, 108, 111, 114, 45, 114, 101, 100, 41, 59, 34, 62, 42, 42, 32, 40, 80, 111, ...>>"}, [{Jason, :encode_to_iodata!, 2, [file: 'lib/jason.ex', line: 213, error_info: %{module: Exception}]}, {Phoenix.Socket.V2.JSONSerializer, :encode!, 1, [file: 'lib/phoenix/socket/serializers/v2_json_serializer.ex', line: 72]}, {Phoenix.Socket, :encode_reply, 2, [file: 'lib/phoenix/socket.ex', line: 745]}, {Phoenix.Socket, :handle_in, 4, [file: 'lib/phoenix/socket.ex', line: 642]}, {WebSockAdapter.CowboyAdapter, :websocket_handle, 2, [file: 'lib/websock_adapter/cowboy_adapter.ex', line: 24]}, {:cowboy_websocket, :handler_call, 6, [file: '/Users/Adz/Projects/livebook/deps/cowboy/src/cowboy_websocket.erl', line: 528]}, {:cowboy_http, :loop, 1, [file: '/Users/Adz/Projects/livebook/deps/cowboy/src/cowboy_http.erl', line: 257]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}]} I think the crucial bit being : [{Jason, :encode_to_iodata!, 2, [file: 'lib/jason.ex', line: 213, error_info: %{module: Exception}]}, {Phoenix.Socket.V2.JSONSerializer, :encode!, 1, The logged message is: <<27, 91, 51, 49, 109, 42, 42, 32, 40, 80, 111, 115, 116, 103, 114, 101, 120,
46, 69, 114, 114, 111, 114, 41, 32, 69, 82, 82, 79, 82, 32, 50, 50, 48, 50,
49, 32, 40, 99, 104, 97, 114, 97, 99, 116, 101, 114, 95, 110, 111, 116, 95,
105, 110, 95, 114, 101, 112, 101, 114, 116, 111, 105, 114, 101, 41, 32, 105,
110, 118, 97, 108, 105, 100, 32, 98, 121, 116, 101, 32, 115, 101, 113, 117,
101, 110, 99, 101, 32, 102, 111, 114, 32, 101, 110, 99, 111, 100, 105, 110,
103, 32, 34, 85, 84, 70, 56, 34, 58, 32, 48, 120, 98, 100, 10, 10, 32, 32, 32,
32, 113, 117, 101, 114, 121, 58, 32, 83, 69, 76, 69, 67, 84, 32, 115, 48, 46,
34, 105, 100, 34, 44, 32, 115, 48, 46, 34, 110, 97, 109, 101, 34, 44, 32, 115,
48, 46, 34, 111, 114, 100, 101, 114, 34, 44, 32, 115, 48, 46, 34, 109, 101,
110, 117, 95, 105, 100, 34, 44, 32, 115, 48, 46, 34, 105, 110, 115, 101, 114,
116, 101, 100, 95, 97, 116, 34, 44, 32, 115, 48, 46, 34, 117, 112, 100, 97,
116, 101, 100, 95, 97, 116, 34, 32, 70, 82, 79, 77, 32, 34, 115, 117, 98, 95,
109, 101, 110, 117, 115, 34, 32, 65, 83, 32, 115, 48, 32, 87, 72, 69, 82, 69,
32, 40, 115, 48, 46, 34, 105, 100, 34, 32, 61, 32, 39, 1, 127, 101, 209, 128,
189, 21, 45, 249, 151, 175, 166, 221, 51, 160, 15, 39, 41, 27, 91, 48, 109,
10, 27, 91, 51, 49, 109, 32, 32, 32, 32, 40, 101, 99, 116, 111, 95, 115, 113,
108, 32, 51, 46, 57, 46, 48, 41, 32, 108, 105, 98, 47, 101, 99, 116, 111, 47,
97, 100, 97, 112, 116, 101, 114, 115, 47, 115, 113, 108, 46, 101, 120, 58, 57,
48, 53, 58, 32, 69, 99, 116, 111, 46, 65, 100, 97, 112, 116, 101, 114, 115,
46, 83, 81, 76, 46, 114, 97, 105, 115, 101, 95, 115, 113, 108, 95, 99, 97,
108, 108, 95, 101, 114, 114, 111, 114, 47, 49, 10, 32, 32, 32, 32, 40, 101,
99, 116, 111, 95, 115, 113, 108, 32, 51, 46, 57, 46, 48, 41, 32, 108, 105, 98,
47, 101, 99, 116, 111, 47, 97, 100, 97, 112, 116, 101, 114, 115, 47, 115, 113,
108, 46, 101, 120, 58, 56, 50, 48, 58, 32, 69, 99, 116, 111, 46, 65, 100, 97,
112, 116, 101, 114, 115, 46, 83, 81, 76, 46, 101, 120, 101, 99, 117, 116, 101,
47, 54, 10, 32, 32, 32, 32, 40, 101, 99, 116, 111, 32, 51, 46, 57, 46, 49, 41,
32, 108, 105, 98, 47, 101, 99, 116, 111, 47, 114, 101, 112, 111, 47, 113, 117,
101, 114, 121, 97, 98, 108, 101, 46, 101, 120, 58, 50, 50, 57, 58, 32, 69, 99,
116, 111, 46, 82, 101, 112, 111, 46, 81, 117, 101, 114, 121, 97, 98, 108, 101,
46, 101, 120, 101, 99, 117, 116, 101, 47, 52, 10, 32, 32, 32, 32, 40, 101, 99,
116, 111, 32, 51, 46, 57, 46, 49, 41, 32, 108, 105, 98, 47, 101, 99, 116, 111,
47, 114, 101, 112, 111, 47, 113, 117, 101, 114, 121, 97, 98, 108, 101, 46,
101, 120, 58, 49, 57, 58, 32, 69, 99, 116, 111, 46, 82, 101, 112, 111, 46, 81,
117, 101, 114, 121, 97, 98, 108, 101, 46, 97, 108, 108, 47, 51, 10, 32, 32,
32, 32, 35, 99, 101, 108, 108, 58, 114, 99, 110, 111, 115, 107, 108, 120, 117,
54, 116, 103, 102, 55, 116, 55, 103, 55, 117, 111, 106, 97, 100, 97, 121, 97,
55, 121, 50, 110, 119, 109, 58, 52, 58, 32, 40, 102, 105, 108, 101, 41, 10,
32, 32, 32, 32, 40, 115, 116, 100, 108, 105, 98, 32, 52, 46, 49, 46, 49, 41,
32, 101, 114, 108, 95, 101, 118, 97, 108, 46, 101, 114, 108, 58, 55, 52, 56,
58, 32, 58, 101, 114, 108, 95, 101, 118, 97, 108, 46, 100, 111, 95, 97, 112,
112, 108, 121, 47, 55, 10, 32, 32, 32, 32, 40, 101, 108, 105, 120, 105, 114,
32, 49, 46, 49, 52, 46, 50, 41, 32, 108, 105, 98, 47, 109, 111, 100, 117, 108,
101, 47, 112, 97, 114, 97, 108, 108, 101, 108, 95, 99, 104, 101, 99, 107, 101,
114, 46, 101, 120, 58, 49, 48, 55, 58, 32, 77, 111, 100, 117, 108, 101, 46,
80, 97, 114, 97, 108, 108, 101, 108, 67, 104, 101, 99, 107, 101, 114, 46, 118,
101, 114, 105, 102, 121, 47, 49, 10, 27, 91, 48, 109>> Which makes it seem like there are non valid JSON chars in the error message? |
Doing this: String.codepoints(message) |> Enum.filter(&String.printable?/1) |> Enum.join() |> IO.puts Yields: ** (Postgrex.Error) ERROR 22021 (character_not_in_repertoire) invalid byte sequence for encoding "UTF8": 0xbd
query: SELECT s0."id", s0."name", s0."order", s0."menu_id", s0."inserted_at", s0."updated_at" FROM "sub_menus" AS s0 WHERE (s0."id" = '^�eр-3')
(ecto_sql 3.9.0) lib/ecto/adapters/sql.ex:905: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto_sql 3.9.0) lib/ecto/adapters/sql.ex:820: Ecto.Adapters.SQL.execute/6
(ecto 3.9.1) lib/ecto/repo/queryable.ex:229: Ecto.Repo.Queryable.execute/4
(ecto 3.9.1) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
#cell:rcnosklxu6tgf7t7g7uojadaya7y2nwm:4: (file)
(stdlib 4.1.1) erl_eval.erl:748: :erl_eval.do_apply/7
(elixir 1.14.2) lib/module/parallel_checker.ex:107: Module.ParallelChecker.verify/1 |
Thank you! I have some thoughts about this. What is the type for the ID field of Db.SubMenu? I have tried reproducing this issue in Ecto, using :uuid or :binary_id, and it precisely tells me to use
if it is a binary, it gets interpolated as a bytea:
which is a valid SQL queries. In any case, it is clear we are failing to encode the error message, so we need to either allow more data to be encoded (which would help this issue: livebook-dev/kino_db#56) or we would need to add similar safe-guards. Btw, @jonatanklosko, I had an idea! Instead of doing our own Jason encoding and then sending it as binary in js_view_channel, perhaps we could do our own encoding and wrap it inside a Jason.Fragment? |
The ID is a custom ecto type, a ULID: (adapted from here defmodule Ecto.ULID do
@moduledoc """
An Ecto type for ULID strings. This is copied from https://github.com/TheRealReal/ecto-ulid
which seems unmaintained. Should probably fork and make it a package.
"""
use Ecto.Type
@doc """
The underlying schema type.
"""
def type, do: :uuid
def embed_as(_), do: :self
def equal?(term1, term2), do: term1 == term2
@doc """
Casts a string to ULID.
"""
def cast(<<_::bytes-size(26)>> = value) do
if valid?(value) do
{:ok, value}
else
:error
end
end
def cast(_), do: :error
@doc """
Same as `cast/1` but raises `Ecto.CastError` on invalid arguments.
"""
def cast!(value) do
case cast(value) do
{:ok, ulid} -> ulid
:error -> raise Ecto.CastError, type: __MODULE__, value: value
end
end
@doc """
Converts a Crockford Base32 encoded ULID into a binary.
"""
def dump(<<_::bytes-size(26)>> = encoded), do: decode(encoded)
def dump(_), do: :error
@doc """
Converts a binary ULID into a Crockford Base32 encoded string.
"""
def load(<<_::unsigned-size(128)>> = bytes), do: encode(bytes)
def load(_), do: :error
@doc false
def autogenerate, do: generate()
@doc """
Generates a Crockford Base32 encoded ULID.
If a value is provided for `timestamp`, the generated ULID will be for the provided timestamp.
Otherwise, a ULID will be generated for the current time.
Arguments:
* `timestamp`: A Unix timestamp with millisecond precision.
"""
def generate(timestamp \\ System.system_time(:millisecond)) do
{:ok, ulid} = encode(bingenerate(timestamp))
ulid
end
@doc """
Generates a binary ULID.
If a value is provided for `timestamp`, the generated ULID will be for the provided timestamp.
Otherwise, a ULID will be generated for the current time.
Arguments:
* `timestamp`: A Unix timestamp with millisecond precision.
"""
def bingenerate(timestamp \\ System.system_time(:millisecond)) do
<<timestamp::unsigned-size(48), :crypto.strong_rand_bytes(10)::binary>>
end
defp encode(
<<b1::3, b2::5, b3::5, b4::5, b5::5, b6::5, b7::5, b8::5, b9::5, b10::5, b11::5, b12::5,
b13::5, b14::5, b15::5, b16::5, b17::5, b18::5, b19::5, b20::5, b21::5, b22::5, b23::5,
b24::5, b25::5, b26::5>>
) do
<<e(b1), e(b2), e(b3), e(b4), e(b5), e(b6), e(b7), e(b8), e(b9), e(b10), e(b11), e(b12),
e(b13), e(b14), e(b15), e(b16), e(b17), e(b18), e(b19), e(b20), e(b21), e(b22), e(b23),
e(b24), e(b25), e(b26)>>
catch
:error -> :error
else
encoded -> {:ok, encoded}
end
defp encode(_), do: :error
@compile {:inline, e: 1}
defp e(0), do: ?0
defp e(1), do: ?1
defp e(2), do: ?2
defp e(3), do: ?3
defp e(4), do: ?4
defp e(5), do: ?5
defp e(6), do: ?6
defp e(7), do: ?7
defp e(8), do: ?8
defp e(9), do: ?9
defp e(10), do: ?A
defp e(11), do: ?B
defp e(12), do: ?C
defp e(13), do: ?D
defp e(14), do: ?E
defp e(15), do: ?F
defp e(16), do: ?G
defp e(17), do: ?H
defp e(18), do: ?J
defp e(19), do: ?K
defp e(20), do: ?M
defp e(21), do: ?N
defp e(22), do: ?P
defp e(23), do: ?Q
defp e(24), do: ?R
defp e(25), do: ?S
defp e(26), do: ?T
defp e(27), do: ?V
defp e(28), do: ?W
defp e(29), do: ?X
defp e(30), do: ?Y
defp e(31), do: ?Z
defp decode(
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8, c9::8, c10::8, c11::8, c12::8,
c13::8, c14::8, c15::8, c16::8, c17::8, c18::8, c19::8, c20::8, c21::8, c22::8, c23::8,
c24::8, c25::8, c26::8>>
) do
<<d(c1)::3, d(c2)::5, d(c3)::5, d(c4)::5, d(c5)::5, d(c6)::5, d(c7)::5, d(c8)::5, d(c9)::5,
d(c10)::5, d(c11)::5, d(c12)::5, d(c13)::5, d(c14)::5, d(c15)::5, d(c16)::5, d(c17)::5,
d(c18)::5, d(c19)::5, d(c20)::5, d(c21)::5, d(c22)::5, d(c23)::5, d(c24)::5, d(c25)::5,
d(c26)::5>>
catch
:error -> :error
else
decoded -> {:ok, decoded}
end
defp decode(_), do: :error
@compile {:inline, d: 1}
defp d(?0), do: 0
defp d(?1), do: 1
defp d(?2), do: 2
defp d(?3), do: 3
defp d(?4), do: 4
defp d(?5), do: 5
defp d(?6), do: 6
defp d(?7), do: 7
defp d(?8), do: 8
defp d(?9), do: 9
defp d(?A), do: 10
defp d(?B), do: 11
defp d(?C), do: 12
defp d(?D), do: 13
defp d(?E), do: 14
defp d(?F), do: 15
defp d(?G), do: 16
defp d(?H), do: 17
defp d(?J), do: 18
defp d(?K), do: 19
defp d(?M), do: 20
defp d(?N), do: 21
defp d(?P), do: 22
defp d(?Q), do: 23
defp d(?R), do: 24
defp d(?S), do: 25
defp d(?T), do: 26
defp d(?V), do: 27
defp d(?W), do: 28
defp d(?X), do: 29
defp d(?Y), do: 30
defp d(?Z), do: 31
defp d(_), do: throw(:error)
defp valid?(
<<c1::8, c2::8, c3::8, c4::8, c5::8, c6::8, c7::8, c8::8, c9::8, c10::8, c11::8, c12::8,
c13::8, c14::8, c15::8, c16::8, c17::8, c18::8, c19::8, c20::8, c21::8, c22::8, c23::8,
c24::8, c25::8, c26::8>>
) do
v(c1) && v(c2) && v(c3) && v(c4) && v(c5) && v(c6) && v(c7) && v(c8) && v(c9) && v(c10) &&
v(c11) && v(c12) && v(c13) &&
v(c14) && v(c15) && v(c16) && v(c17) && v(c18) && v(c19) && v(c20) && v(c21) && v(c22) &&
v(c23) && v(c24) && v(c25) && v(c26)
end
defp valid?(_), do: false
@compile {:inline, v: 1}
defp v(?0), do: true
defp v(?1), do: true
defp v(?2), do: true
defp v(?3), do: true
defp v(?4), do: true
defp v(?5), do: true
defp v(?6), do: true
defp v(?7), do: true
defp v(?8), do: true
defp v(?9), do: true
defp v(?A), do: true
defp v(?B), do: true
defp v(?C), do: true
defp v(?D), do: true
defp v(?E), do: true
defp v(?F), do: true
defp v(?G), do: true
defp v(?H), do: true
defp v(?J), do: true
defp v(?K), do: true
defp v(?M), do: true
defp v(?N), do: true
defp v(?P), do: true
defp v(?Q), do: true
defp v(?R), do: true
defp v(?S), do: true
defp v(?T), do: true
defp v(?V), do: true
defp v(?W), do: true
defp v(?X), do: true
defp v(?Y), do: true
defp v(?Z), do: true
defp v(_), do: false
end |
Ah, perfect. I got the underlying UUID, converted it to |
Closing this for now. The discussion can now continue on livebook-dev/kino_db#56. |
I'm not sure how to help reproduce this, but I have a livebook attached to an app via connected node. I run this cell:
Livebook freezes the cell never stops and I see this output (in the shell):
Then an error log repeats indefinitely:
What's really strange is if I do this in that same cell it's fine:
Environment
livebook server .
in shellgit rev-parse HEAD
if running with mix): latestThe text was updated successfully, but these errors were encountered: